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 "raw_file_manager.h"
17
18 #include <climits>
19 #include <cstdio>
20 #include <cstdlib>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <securec.h>
24 #include <unistd.h>
25
26 #include "raw_dir.h"
27 #include "raw_file.h"
28 #include "resource_manager.h"
29 #include "resource_manager_addon.h"
30 #include "resource_manager_impl.h"
31 #include "hilog/log_c.h"
32 #include "hilog/log_cpp.h"
33
34 #ifdef __WINNT__
35 #include <shlwapi.h>
36 #include <windows.h>
37 #endif
38
39 using namespace OHOS::Global::Resource;
40 using namespace OHOS::HiviewDFX;
41
42 namespace {
43 constexpr HiLogLabel LABEL = {LOG_CORE, 0xD001E00, "RawFile"};
44 }
45
46 struct NativeResourceManager {
47 std::shared_ptr<ResourceManager> resManager = nullptr;
48 };
49
50 struct FileNameCache {
51 std::vector<std::string> names;
52 };
53
54 struct RawDir {
55 std::shared_ptr<ResourceManager> resManager = nullptr;
56 struct FileNameCache fileNameCache;
57 };
58
59 struct RawFile {
60 const std::string filePath;
61 long offset;
62 long length;
63 FILE* pf;
64 uint8_t* buffer;
65 const NativeResourceManager *resMgr;
66
RawFileRawFile67 explicit RawFile(const std::string &path) : filePath(path), offset(0L), length(0L),
68 pf(nullptr), buffer(nullptr), resMgr{nullptr} {}
69
~RawFileRawFile70 ~RawFile()
71 {
72 if (buffer != nullptr) {
73 free(buffer);
74 buffer = nullptr;
75 }
76 if (pf != nullptr) {
77 fclose(pf);
78 pf = nullptr;
79 }
80 }
81
openRawFile82 bool open()
83 {
84 pf = std::fopen(filePath.c_str(), "rb");
85 return pf != nullptr;
86 }
87 };
88
OH_ResourceManager_InitNativeResourceManager(napi_env env,napi_value jsResMgr)89 NativeResourceManager *OH_ResourceManager_InitNativeResourceManager(napi_env env, napi_value jsResMgr)
90 {
91 napi_valuetype valueType;
92 napi_typeof(env, jsResMgr, &valueType);
93 if (valueType != napi_object) {
94 HiLog::Error(LABEL, "jsResMgr is not an object");
95 return nullptr;
96 }
97 std::shared_ptr<ResourceManagerAddon> *addonPtr = nullptr;
98 napi_status status = napi_unwrap(env, jsResMgr, reinterpret_cast<void **>(&addonPtr));
99 if (status != napi_ok) {
100 HiLog::Error(LABEL, "Failed to get native resourcemanager");
101 return nullptr;
102 }
103 std::unique_ptr<NativeResourceManager> result = std::make_unique<NativeResourceManager>();
104 result->resManager = (*addonPtr)->GetResMgr();
105 return result.release();
106 }
107
OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager * resMgr)108 void OH_ResourceManager_ReleaseNativeResourceManager(NativeResourceManager *resMgr)
109 {
110 if (resMgr != nullptr) {
111 delete resMgr;
112 resMgr = nullptr;
113 }
114 }
115
IsLoadHap(const NativeResourceManager * mgr,std::string & hapPath)116 static bool IsLoadHap(const NativeResourceManager *mgr, std::string &hapPath)
117 {
118 return mgr->resManager->IsLoadHap(hapPath) == RState::SUCCESS ? true : false;
119 }
120
LoadRawDirFromHap(const NativeResourceManager * mgr,const std::string dirName)121 RawDir *LoadRawDirFromHap(const NativeResourceManager *mgr, const std::string dirName)
122 {
123 std::unique_ptr<RawDir> result = std::make_unique<RawDir>();
124 RState state = mgr->resManager->GetRawFileList(dirName, result->fileNameCache.names);
125 if (state != RState::SUCCESS) {
126 HiLog::Error(LABEL, "failed to get RawDir dirName, %{public}s", dirName.c_str());
127 return nullptr;
128 }
129 return result.release();
130 }
131
OH_ResourceManager_OpenRawDir(const NativeResourceManager * mgr,const char * dirName)132 RawDir *OH_ResourceManager_OpenRawDir(const NativeResourceManager *mgr, const char *dirName)
133 {
134 if (mgr == nullptr || dirName == nullptr) {
135 return nullptr;
136 }
137 std::string hapPath;
138 if (IsLoadHap(mgr, hapPath)) {
139 return LoadRawDirFromHap(mgr, dirName);
140 }
141 ResourceManagerImpl* impl = static_cast<ResourceManagerImpl *>(mgr->resManager.get());
142 std::string tempName = dirName;
143 const std::string rawFileDirName = tempName.empty() ? "rawfile" : "rawfile/";
144 if (tempName.length() < rawFileDirName.length()
145 || (tempName.compare(0, rawFileDirName.length(), rawFileDirName) != 0)) {
146 tempName = rawFileDirName + tempName;
147 }
148 std::unique_ptr<RawDir> result = std::make_unique<RawDir>();
149 std::vector<std::string> resourcesPaths = impl->GetResourcePaths();
150 for (auto iter = resourcesPaths.begin(); iter != resourcesPaths.end(); iter++) {
151 std::string currentPath = *iter + tempName;
152 DIR* dir = opendir(currentPath.c_str());
153 if (dir == nullptr) {
154 continue;
155 }
156 struct dirent *dirp = readdir(dir);
157 while (dirp != nullptr) {
158 if (std::strcmp(dirp->d_name, ".") == 0 ||
159 std::strcmp(dirp->d_name, "..") == 0) {
160 dirp = readdir(dir);
161 continue;
162 }
163 if (dirp->d_type == DT_REG || dirp->d_type == DT_DIR) {
164 result->fileNameCache.names.push_back(tempName + "/" + dirp->d_name);
165 }
166
167 dirp = readdir(dir);
168 }
169 closedir(dir);
170 }
171 return result.release();
172 }
173
LoadRawFileFromHap(const NativeResourceManager * mgr,const char * fileName,const std::string hapPath)174 RawFile *LoadRawFileFromHap(const NativeResourceManager *mgr, const char *fileName, const std::string hapPath)
175 {
176 size_t len;
177 std::unique_ptr<uint8_t[]> tmpBuf;
178 RState state = mgr->resManager->GetRawFileFromHap(fileName, len, tmpBuf);
179 if (state != SUCCESS) {
180 HiLog::Error(LABEL, "failed to get %{public}s rawfile", fileName);
181 return nullptr;
182 }
183 auto result = std::make_unique<RawFile>(fileName);
184 result->buffer = reinterpret_cast<uint8_t*>(malloc(len));
185 if (result->buffer == nullptr) {
186 HiLog::Error(LABEL, "failed to malloc");
187 return nullptr;
188 }
189 int ret = memcpy_s(result->buffer, len, tmpBuf.get(), len);
190 if (ret != 0) {
191 HiLog::Error(LABEL, "failed to memcpy_s");
192 return nullptr;
193 }
194
195 int zipFd = open(hapPath.c_str(), O_RDONLY);
196 if (zipFd < 0) {
197 HiLog::Error(LABEL, "failed open file %{public}s", hapPath.c_str());
198 return nullptr;
199 }
200 result->pf = fdopen(zipFd, "r");
201 result->length = static_cast<long>(len);
202 result->resMgr = mgr;
203 return result.release();
204 }
205
OH_ResourceManager_OpenRawFile(const NativeResourceManager * mgr,const char * fileName)206 RawFile *OH_ResourceManager_OpenRawFile(const NativeResourceManager *mgr, const char *fileName)
207 {
208 if (mgr == nullptr || fileName == nullptr) {
209 return nullptr;
210 }
211
212 std::string hapPath;
213 if (IsLoadHap(mgr, hapPath)) {
214 return LoadRawFileFromHap(mgr, fileName, hapPath);
215 }
216
217 std::string filePath;
218 RState state = mgr->resManager->GetRawFilePathByName(fileName, filePath);
219 if (state != SUCCESS) {
220 return nullptr;
221 }
222 std::unique_ptr<RawFile> result = std::make_unique<RawFile>(filePath);
223 if (!result->open()) {
224 return nullptr;
225 }
226
227 std::fseek(result->pf, 0, SEEK_END);
228 result->length = ftell(result->pf);
229 std::fseek(result->pf, 0, SEEK_SET);
230 return result.release();
231 }
232
OH_ResourceManager_GetRawFileCount(RawDir * rawDir)233 int OH_ResourceManager_GetRawFileCount(RawDir *rawDir)
234 {
235 if (rawDir == nullptr) {
236 return 0;
237 }
238 return rawDir->fileNameCache.names.size();
239 }
240
OH_ResourceManager_GetRawFileName(RawDir * rawDir,int index)241 const char *OH_ResourceManager_GetRawFileName(RawDir *rawDir, int index)
242 {
243 if (rawDir == nullptr || index < 0) {
244 return nullptr;
245 }
246 uint32_t rawFileCount = rawDir->fileNameCache.names.size();
247 if (rawFileCount == 0 || index >= static_cast<int>(rawFileCount)) {
248 return nullptr;
249 }
250 return rawDir->fileNameCache.names[index].c_str();
251 }
252
OH_ResourceManager_CloseRawDir(RawDir * rawDir)253 void OH_ResourceManager_CloseRawDir(RawDir *rawDir)
254 {
255 if (rawDir != nullptr) {
256 delete rawDir;
257 }
258 }
259
OH_ResourceManager_ReadRawFile(const RawFile * rawFile,void * buf,size_t length)260 int OH_ResourceManager_ReadRawFile(const RawFile *rawFile, void *buf, size_t length)
261 {
262 if (rawFile == nullptr || buf == nullptr || length == 0) {
263 return 0;
264 }
265 if (rawFile->buffer != nullptr) {
266 int ret = memcpy_s(buf, length, rawFile->buffer, rawFile->length);
267 if (ret != 0) {
268 HiLog::Error(LABEL, "failed to copy to buf");
269 return 0;
270 }
271 return rawFile->length;
272 } else {
273 return std::fread(buf, 1, length, rawFile->pf);
274 }
275 }
276
OH_ResourceManager_SeekRawFile(const RawFile * rawFile,long offset,int whence)277 int OH_ResourceManager_SeekRawFile(const RawFile *rawFile, long offset, int whence)
278 {
279 if (rawFile == nullptr) {
280 return 0;
281 }
282
283 int origin = 0;
284 int start = 0;
285 switch (whence) {
286 case SEEK_SET:
287 origin = SEEK_SET;
288 start = rawFile->offset + offset;
289 break;
290 case SEEK_CUR:
291 origin = SEEK_CUR;
292 start = offset;
293 break;
294 case SEEK_END:
295 start = rawFile->offset + rawFile->length + offset;
296 origin = SEEK_SET;
297 break;
298 default:
299 return -1;
300 }
301
302 return std::fseek(rawFile->pf, start, origin);
303 }
304
OH_ResourceManager_GetRawFileSize(RawFile * rawFile)305 long OH_ResourceManager_GetRawFileSize(RawFile *rawFile)
306 {
307 if (rawFile == nullptr) {
308 return 0;
309 }
310
311 return rawFile->length;
312 }
313
OH_ResourceManager_CloseRawFile(RawFile * rawFile)314 void OH_ResourceManager_CloseRawFile(RawFile *rawFile)
315 {
316 if (rawFile != nullptr) {
317 delete rawFile;
318 }
319 }
320
OH_ResourceManager_GetRawFileOffset(const RawFile * rawFile)321 long OH_ResourceManager_GetRawFileOffset(const RawFile *rawFile)
322 {
323 if (rawFile == nullptr) {
324 return 0;
325 }
326 return ftell(rawFile->pf) - rawFile->offset;
327 }
328
GetRawFileDescriptorFromHap(const RawFile * rawFile,RawFileDescriptor & descriptor)329 static bool GetRawFileDescriptorFromHap(const RawFile *rawFile, RawFileDescriptor &descriptor)
330 {
331 ResourceManager::RawFileDescriptor resMgrDescriptor;
332 int32_t ret = rawFile->resMgr->resManager->GetRawFileDescriptorFromHap(rawFile->filePath, resMgrDescriptor);
333 if (ret != 0) {
334 HiLog::Error(LABEL, "failed to get rawFile descriptor");
335 return false;
336 }
337 descriptor.fd = resMgrDescriptor.fd;
338 descriptor.length = resMgrDescriptor.length;
339 descriptor.start = resMgrDescriptor.offset;
340 return true;
341 }
342
OH_ResourceManager_GetRawFileDescriptor(const RawFile * rawFile,RawFileDescriptor & descriptor)343 bool OH_ResourceManager_GetRawFileDescriptor(const RawFile *rawFile, RawFileDescriptor &descriptor)
344 {
345 if (rawFile == nullptr) {
346 return false;
347 }
348 if (rawFile->resMgr != nullptr) {
349 return GetRawFileDescriptorFromHap(rawFile, descriptor);
350 }
351 char paths[PATH_MAX] = {0};
352 #ifdef __WINNT__
353 if (!PathCanonicalizeA(paths, rawFile->filePath.c_str())) {
354 HiLog::Error(LABEL, "failed to PathCanonicalizeA the rawFile path");
355 }
356 #else
357 if (realpath(rawFile->filePath.c_str(), paths) == nullptr) {
358 HiLog::Error(LABEL, "failed to realpath the rawFile path");
359 }
360 #endif
361 int fd = open(paths, O_RDONLY);
362 if (fd > 0) {
363 descriptor.fd = fd;
364 descriptor.length = rawFile->length;
365 descriptor.start = rawFile->offset;
366 } else {
367 return false;
368 }
369 return true;
370 }
371
OH_ResourceManager_ReleaseRawFileDescriptor(const RawFileDescriptor & descriptor)372 bool OH_ResourceManager_ReleaseRawFileDescriptor(const RawFileDescriptor &descriptor)
373 {
374 if (descriptor.fd > 0) {
375 return close(descriptor.fd) == 0;
376 }
377 return true;
378 }
379