1 /*
2 * Copyright (c) 2021-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 "installd/installd_operator.h"
17
18 #include <algorithm>
19 #include <cstdio>
20 #include <dirent.h>
21 #include <dlfcn.h>
22 #include <fstream>
23 #include <map>
24 #include <sstream>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include "app_log_wrapper.h"
31 #include "bundle_constants.h"
32 #include "directory_ex.h"
33 #include "parameters.h"
34
35 namespace OHOS {
36 namespace AppExecFwk {
37 namespace {
38 static const char LIB_DIFF_PATCH_SHARED_SO_PATH[] = "system/lib/libdiff_patch_shared.z.so";
39 static const char LIB64_DIFF_PATCH_SHARED_SO_PATH[] = "system/lib64/libdiff_patch_shared.z.so";
40 static const char APPLY_PATCH_FUNCTION_NAME[] = "ApplyPatch";
41 using ApplyPatch = int32_t (*)(const std::string, const std::string, const std::string);
42
HandleScanResult(const std::string & dir,const std::string & subName,ResultMode resultMode)43 static std::string HandleScanResult(
44 const std::string &dir, const std::string &subName, ResultMode resultMode)
45 {
46 if (resultMode == ResultMode::RELATIVE_PATH) {
47 return subName;
48 }
49
50 return dir + Constants::PATH_SEPARATOR + subName;
51 }
52 }
53
IsExistFile(const std::string & path)54 bool InstalldOperator::IsExistFile(const std::string &path)
55 {
56 if (path.empty()) {
57 return false;
58 }
59
60 struct stat buf = {};
61 if (stat(path.c_str(), &buf) != 0) {
62 return false;
63 }
64 return S_ISREG(buf.st_mode);
65 }
66
IsExistDir(const std::string & path)67 bool InstalldOperator::IsExistDir(const std::string &path)
68 {
69 if (path.empty()) {
70 return false;
71 }
72
73 struct stat buf = {};
74 if (stat(path.c_str(), &buf) != 0) {
75 return false;
76 }
77 return S_ISDIR(buf.st_mode);
78 }
79
IsDirEmpty(const std::string & dir)80 bool InstalldOperator::IsDirEmpty(const std::string &dir)
81 {
82 return OHOS::IsEmptyFolder(dir);
83 }
84
MkRecursiveDir(const std::string & path,bool isReadByOthers)85 bool InstalldOperator::MkRecursiveDir(const std::string &path, bool isReadByOthers)
86 {
87 if (!OHOS::ForceCreateDirectory(path)) {
88 APP_LOGE("mkdir failed");
89 return false;
90 }
91 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH;
92 mode |= (isReadByOthers ? S_IROTH : 0);
93 return OHOS::ChangeModeDirectory(path, mode);
94 }
95
DeleteDir(const std::string & path)96 bool InstalldOperator::DeleteDir(const std::string &path)
97 {
98 if (IsExistFile(path)) {
99 return OHOS::RemoveFile(path);
100 }
101 if (IsExistDir(path)) {
102 return OHOS::ForceRemoveDirectory(path);
103 }
104 return true;
105 }
106
ExtractFiles(const std::string & sourcePath,const std::string & targetPath,const std::string & targetSoPath,const std::string & cpuAbi)107 bool InstalldOperator::ExtractFiles(const std::string &sourcePath, const std::string &targetPath,
108 const std::string &targetSoPath, const std::string &cpuAbi)
109 {
110 APP_LOGD("InstalldOperator::ExtractFiles start");
111 BundleExtractor extractor(sourcePath);
112 if (!extractor.Init()) {
113 return false;
114 }
115 std::vector<std::string> entryNames;
116 if (!extractor.GetZipFileNames(entryNames)) {
117 return false;
118 }
119 if (entryNames.empty()) {
120 return false;
121 }
122
123 std::string targetDir = targetPath;
124 if (targetPath.back() != Constants::PATH_SEPARATOR[0]) {
125 targetDir = targetPath + Constants::PATH_SEPARATOR;
126 }
127 for (const auto &entryName : entryNames) {
128 if (strcmp(entryName.c_str(), ".") == 0 ||
129 strcmp(entryName.c_str(), "..") == 0) {
130 continue;
131 }
132 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
133 continue;
134 }
135 // handle native so
136 if (IsNativeSo(entryName, targetSoPath, cpuAbi)) {
137 ExtractTargetFile(extractor, entryName, targetSoPath, cpuAbi);
138 continue;
139 }
140 if (system::GetBoolParameter(Constants::COMPRESS_PROPERTY, false)) {
141 continue;
142 }
143 const std::string dir = GetPathDir(entryName);
144 std::string filePath = targetDir + dir;
145 if (!dir.empty()) {
146 if (!MkRecursiveDir(filePath, true)) {
147 return false;
148 }
149 }
150 filePath = targetDir + entryName;
151 if (!extractor.ExtractFile(entryName, filePath)) {
152 return false;
153 }
154 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
155 if (!OHOS::ChangeModeFile(filePath, mode)) {
156 APP_LOGE("change mode failed");
157 }
158 filePath.clear();
159 }
160 APP_LOGD("InstalldOperator::ExtractFiles end");
161 return true;
162 }
163
ExtractFiles(const ExtractParam & extractParam)164 bool InstalldOperator::ExtractFiles(const ExtractParam &extractParam)
165 {
166 APP_LOGD("InstalldOperator::ExtractFiles start");
167 BundleExtractor extractor(extractParam.srcPath);
168 if (!extractor.Init()) {
169 APP_LOGE("extractor init failed");
170 return false;
171 }
172
173 if ((extractParam.extractFileType == ExtractFileType::AP) &&
174 !extractor.IsDirExist(Constants::AP)) {
175 APP_LOGD("hap has no ap files and does not need to be extracted.");
176 return true;
177 }
178
179 std::vector<std::string> entryNames;
180 if (!extractor.GetZipFileNames(entryNames) || entryNames.empty()) {
181 APP_LOGE("get entryNames failed");
182 return false;
183 }
184
185 for (const auto &entryName : entryNames) {
186 if (strcmp(entryName.c_str(), ".") == 0 ||
187 strcmp(entryName.c_str(), "..") == 0) {
188 continue;
189 }
190 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
191 continue;
192 }
193 // handle native file
194 if (IsNativeFile(entryName, extractParam)) {
195 ExtractTargetFile(extractor, entryName, extractParam.targetPath,
196 extractParam.cpuAbi, extractParam.extractFileType);
197 continue;
198 }
199 }
200
201 APP_LOGD("InstalldOperator::ExtractFiles end");
202 return true;
203 }
204
IsNativeFile(const std::string & entryName,const ExtractParam & extractParam)205 bool InstalldOperator::IsNativeFile(
206 const std::string &entryName, const ExtractParam &extractParam)
207 {
208 APP_LOGD("IsNativeFile, entryName : %{public}s", entryName.c_str());
209 if (extractParam.targetPath.empty()) {
210 APP_LOGD("current hap not include so");
211 return false;
212 }
213 std::string prefix;
214 std::vector<std::string> suffixs;
215 switch (extractParam.extractFileType) {
216 case ExtractFileType::SO: {
217 prefix = Constants::LIBS + extractParam.cpuAbi + Constants::PATH_SEPARATOR;
218 suffixs.emplace_back(Constants::SO_SUFFIX);
219 break;
220 }
221 case ExtractFileType::AN: {
222 prefix = Constants::AN + extractParam.cpuAbi + Constants::PATH_SEPARATOR;
223 suffixs.emplace_back(Constants::AN_SUFFIX);
224 suffixs.emplace_back(Constants::AI_SUFFIX);
225 break;
226 }
227 case ExtractFileType::AP: {
228 prefix = Constants::AP;
229 suffixs.emplace_back(Constants::AP_SUFFIX);
230 break;
231 }
232 default: {
233 return false;
234 }
235 }
236
237 if (entryName.find(prefix) == std::string::npos) {
238 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
239 return false;
240 }
241
242 bool checkSuffix = false;
243 for (const auto &suffix : suffixs) {
244 if (entryName.find(suffix) != std::string::npos) {
245 checkSuffix = true;
246 break;
247 }
248 }
249
250 if (!checkSuffix) {
251 APP_LOGD("file type error.");
252 return false;
253 }
254
255 APP_LOGD("find native file, prefix: %{public}s, entryName: %{public}s",
256 prefix.c_str(), entryName.c_str());
257 return true;
258 }
259
IsNativeSo(const std::string & entryName,const std::string & targetSoPath,const std::string & cpuAbi)260 bool InstalldOperator::IsNativeSo(const std::string &entryName,
261 const std::string &targetSoPath, const std::string &cpuAbi)
262 {
263 APP_LOGD("IsNativeSo, entryName : %{public}s", entryName.c_str());
264 if (targetSoPath.empty()) {
265 APP_LOGD("current hap not include so");
266 return false;
267 }
268 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
269 if (entryName.find(prefix) == std::string::npos) {
270 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
271 return false;
272 }
273 if (entryName.find(Constants::SO_SUFFIX) == std::string::npos) {
274 APP_LOGD("file name not so format.");
275 return false;
276 }
277 APP_LOGD("find native so, entryName : %{public}s", entryName.c_str());
278 return true;
279 }
280
IsDiffFiles(const std::string & entryName,const std::string & targetPath,const std::string & cpuAbi)281 bool InstalldOperator::IsDiffFiles(const std::string &entryName,
282 const std::string &targetPath, const std::string &cpuAbi)
283 {
284 APP_LOGD("IsDiffFiles, entryName : %{public}s", entryName.c_str());
285 if (targetPath.empty()) {
286 APP_LOGD("current hap not include diff");
287 return false;
288 }
289 std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
290 if (entryName.find(prefix) == std::string::npos) {
291 APP_LOGD("entryName not start with %{public}s", prefix.c_str());
292 return false;
293 }
294 if (entryName.find(Constants::DIFF_SUFFIX) == std::string::npos) {
295 APP_LOGD("file name not diff format.");
296 return false;
297 }
298 APP_LOGD("find native diff, entryName : %{public}s", entryName.c_str());
299 return true;
300 }
301
ExtractTargetFile(const BundleExtractor & extractor,const std::string & entryName,const std::string & targetPath,const std::string & cpuAbi,const ExtractFileType & extractFileType)302 void InstalldOperator::ExtractTargetFile(const BundleExtractor &extractor, const std::string &entryName,
303 const std::string &targetPath, const std::string &cpuAbi, const ExtractFileType &extractFileType)
304 {
305 // create dir if not exist
306 if (!IsExistDir(targetPath)) {
307 if (!MkRecursiveDir(targetPath, true)) {
308 APP_LOGE("create targetPath %{private}s failed", targetPath.c_str());
309 return;
310 }
311 }
312
313 std::string prefix;
314 switch (extractFileType) {
315 case ExtractFileType::SO: {
316 prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
317 break;
318 }
319 case ExtractFileType::AN: {
320 prefix = Constants::AN + cpuAbi + Constants::PATH_SEPARATOR;
321 break;
322 }
323 case ExtractFileType::AP: {
324 prefix = Constants::AP;
325 break;
326 }
327 default: {
328 return;
329 }
330 }
331 std::string targetName = entryName.substr(prefix.length());
332 std::string path = targetPath;
333 if (path.back() != Constants::FILE_SEPARATOR_CHAR) {
334 path += Constants::FILE_SEPARATOR_CHAR;
335 }
336 path += targetName;
337 bool ret = extractor.ExtractFile(entryName, path);
338 if (!ret) {
339 APP_LOGE("extract file failed, entryName : %{public}s", entryName.c_str());
340 return;
341 }
342 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
343 if (extractFileType == ExtractFileType::AP) {
344 struct stat buf = {};
345 if (stat(targetPath.c_str(), &buf) != 0) {
346 return;
347 }
348 ChangeFileAttr(path, buf.st_uid, buf.st_gid);
349 mode = (buf.st_uid == buf.st_gid) ? (S_IRUSR | S_IWUSR) : (S_IRUSR | S_IWUSR | S_IRGRP);
350 }
351 if (!OHOS::ChangeModeFile(path, mode)) {
352 return;
353 }
354 APP_LOGD("extract file success, path : %{private}s", path.c_str());
355 }
356
RenameDir(const std::string & oldPath,const std::string & newPath)357 bool InstalldOperator::RenameDir(const std::string &oldPath, const std::string &newPath)
358 {
359 if (oldPath.empty() || oldPath.size() > PATH_MAX) {
360 APP_LOGE("oldpath error");
361 return false;
362 }
363 if (access(oldPath.c_str(), F_OK) != 0 && access(newPath.c_str(), F_OK) == 0) {
364 return true;
365 }
366 std::string realOldPath;
367 realOldPath.reserve(PATH_MAX);
368 realOldPath.resize(PATH_MAX - 1);
369 if (realpath(oldPath.c_str(), &(realOldPath[0])) == nullptr) {
370 APP_LOGE("realOldPath %{private}s", realOldPath.c_str());
371 return false;
372 }
373
374 if (!(IsValidCodePath(realOldPath) && IsValidCodePath(newPath))) {
375 APP_LOGE("IsValidCodePath failed");
376 return false;
377 }
378 return RenameFile(realOldPath, newPath);
379 }
380
GetPathDir(const std::string & path)381 std::string InstalldOperator::GetPathDir(const std::string &path)
382 {
383 std::size_t pos = path.rfind(Constants::PATH_SEPARATOR);
384 if (pos == std::string::npos) {
385 return std::string();
386 }
387 return path.substr(0, pos + 1);
388 }
389
ChangeDirOwnerRecursively(const std::string & path,const int uid,const int gid)390 bool InstalldOperator::ChangeDirOwnerRecursively(const std::string &path, const int uid, const int gid)
391 {
392 std::string subPath;
393 bool ret = true;
394 DIR *dir = opendir(path.c_str());
395 if (dir == nullptr) {
396 return false;
397 }
398
399 while (true) {
400 struct dirent *ptr = readdir(dir);
401 if (ptr == nullptr) {
402 break;
403 }
404
405 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
406 continue;
407 }
408
409 subPath = OHOS::IncludeTrailingPathDelimiter(path) + std::string(ptr->d_name);
410 if (ptr->d_type == DT_DIR) {
411 ret = ChangeDirOwnerRecursively(subPath, uid, gid);
412 continue;
413 }
414
415 if (access(subPath.c_str(), F_OK) == 0) {
416 if (!ChangeFileAttr(subPath, uid, gid)) {
417 APP_LOGE("Failed to ChangeFileAttr %{public}s", subPath.c_str());
418 closedir(dir);
419 return false;
420 }
421 }
422 }
423
424 closedir(dir);
425 std::string currentPath = OHOS::ExcludeTrailingPathDelimiter(path);
426 if (access(currentPath.c_str(), F_OK) == 0) {
427 if (!ChangeFileAttr(currentPath, uid, gid)) {
428 APP_LOGE("Failed to ChangeFileAttr %{public}s", currentPath.c_str());
429 return false;
430 }
431 }
432
433 return ret;
434 }
435
ChangeFileAttr(const std::string & filePath,const int uid,const int gid)436 bool InstalldOperator::ChangeFileAttr(const std::string &filePath, const int uid, const int gid)
437 {
438 APP_LOGD("begin to change %{private}s file attribute", filePath.c_str());
439 if (chown(filePath.c_str(), uid, gid) != 0) {
440 APP_LOGE("fail to change %{private}s ownership", filePath.c_str());
441 return false;
442 }
443 APP_LOGD("change %{private}s file attribute successfully", filePath.c_str());
444 return true;
445 }
446
RenameFile(const std::string & oldPath,const std::string & newPath)447 bool InstalldOperator::RenameFile(const std::string &oldPath, const std::string &newPath)
448 {
449 if (oldPath.empty() || newPath.empty()) {
450 return false;
451 }
452 if (!DeleteDir(newPath)) {
453 return false;
454 }
455 return rename(oldPath.c_str(), newPath.c_str()) == 0;
456 }
457
IsValidPath(const std::string & rootDir,const std::string & path)458 bool InstalldOperator::IsValidPath(const std::string &rootDir, const std::string &path)
459 {
460 if (rootDir.find(Constants::PATH_SEPARATOR) != 0 ||
461 rootDir.rfind(Constants::PATH_SEPARATOR) != (rootDir.size() - 1) || rootDir.find("..") != std::string::npos) {
462 return false;
463 }
464 if (path.find("..") != std::string::npos) {
465 return false;
466 }
467 return path.compare(0, rootDir.size(), rootDir) == 0;
468 }
469
IsValidCodePath(const std::string & codePath)470 bool InstalldOperator::IsValidCodePath(const std::string &codePath)
471 {
472 if (codePath.empty()) {
473 return false;
474 }
475 return IsValidPath(Constants::BUNDLE_BASE_CODE_DIR + Constants::PATH_SEPARATOR, codePath);
476 }
477
DeleteFiles(const std::string & dataPath)478 bool InstalldOperator::DeleteFiles(const std::string &dataPath)
479 {
480 APP_LOGD("InstalldOperator::DeleteFiles start");
481 std::string subPath;
482 bool ret = true;
483 DIR *dir = opendir(dataPath.c_str());
484 if (dir == nullptr) {
485 return false;
486 }
487 while (true) {
488 struct dirent *ptr = readdir(dir);
489 if (ptr == nullptr) {
490 break;
491 }
492 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
493 continue;
494 }
495 subPath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name);
496 if (ptr->d_type == DT_DIR) {
497 ret = OHOS::ForceRemoveDirectory(subPath);
498 } else {
499 if (access(subPath.c_str(), F_OK) == 0) {
500 ret = OHOS::RemoveFile(subPath);
501 }
502 }
503 }
504 closedir(dir);
505 return ret;
506 }
507
MkOwnerDir(const std::string & path,bool isReadByOthers,const int uid,const int gid)508 bool InstalldOperator::MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid)
509 {
510 if (!MkRecursiveDir(path, isReadByOthers)) {
511 return false;
512 }
513 return ChangeFileAttr(path, uid, gid);
514 }
515
MkOwnerDir(const std::string & path,int mode,const int uid,const int gid)516 bool InstalldOperator::MkOwnerDir(const std::string &path, int mode, const int uid, const int gid)
517 {
518 if (!OHOS::ForceCreateDirectory(path)) {
519 APP_LOGE("mkdir failed");
520 return false;
521 }
522 if (!OHOS::ChangeModeDirectory(path, mode)) {
523 return false;
524 }
525 return ChangeDirOwnerRecursively(path, uid, gid);
526 }
527
GetDiskUsage(const std::string & dir)528 int64_t InstalldOperator::GetDiskUsage(const std::string &dir)
529 {
530 if (dir.empty() || (dir.size() > Constants::PATH_MAX_SIZE)) {
531 APP_LOGE("GetDiskUsage dir path invaild");
532 return 0;
533 }
534 std::string filePath = "";
535 if (!PathToRealPath(dir, filePath)) {
536 APP_LOGE("file is not real path, file path: %{private}s", dir.c_str());
537 return 0;
538 }
539 DIR *dirPtr = opendir(filePath.c_str());
540 if (dirPtr == nullptr) {
541 APP_LOGE("GetDiskUsage open file dir:%{private}s is failure", filePath.c_str());
542 return 0;
543 }
544 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
545 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
546 }
547 struct dirent *entry = nullptr;
548 int64_t size = 0;
549 while ((entry = readdir(dirPtr)) != nullptr) {
550 if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
551 continue;
552 }
553 std::string path = filePath + entry->d_name;
554 std::string realPath = "";
555 if (!PathToRealPath(path, realPath)) {
556 APP_LOGE("file is not real path %{private}s", path.c_str());
557 continue;
558 }
559 struct stat fileInfo = {0};
560 if (stat(realPath.c_str(), &fileInfo) != 0) {
561 APP_LOGE("call stat error %{private}s", realPath.c_str());
562 fileInfo.st_size = 0;
563 }
564 size += fileInfo.st_size;
565 if (entry->d_type == DT_DIR) {
566 size += GetDiskUsage(realPath);
567 }
568 }
569 closedir(dirPtr);
570 return size;
571 }
572
TraverseCacheDirectory(const std::string & currentPath,std::vector<std::string> & cacheDirs)573 void InstalldOperator::TraverseCacheDirectory(const std::string ¤tPath, std::vector<std::string> &cacheDirs)
574 {
575 if (currentPath.empty() || (currentPath.size() > Constants::PATH_MAX_SIZE)) {
576 APP_LOGE("TraverseCacheDirectory current path invaild");
577 return;
578 }
579 std::string filePath = "";
580 if (!PathToRealPath(currentPath, filePath)) {
581 APP_LOGE("file is not real path, file path: %{private}s", currentPath.c_str());
582 return;
583 }
584 DIR* dir = opendir(filePath.c_str());
585 if (dir == nullptr) {
586 return;
587 }
588 if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
589 filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
590 }
591 struct dirent *ptr = nullptr;
592 while ((ptr = readdir(dir)) != nullptr) {
593 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
594 continue;
595 }
596 if (ptr->d_type == DT_DIR && strcmp(ptr->d_name, Constants::CACHE_DIR) == 0) {
597 std::string currentDir = filePath + std::string(ptr->d_name);
598 cacheDirs.emplace_back(currentDir);
599 continue;
600 }
601 if (ptr->d_type == DT_DIR) {
602 std::string currentDir = filePath + std::string(ptr->d_name);
603 TraverseCacheDirectory(currentDir, cacheDirs);
604 }
605 }
606 closedir(dir);
607 }
608
GetDiskUsageFromPath(const std::vector<std::string> & path)609 int64_t InstalldOperator::GetDiskUsageFromPath(const std::vector<std::string> &path)
610 {
611 int64_t fileSize = 0;
612 for (auto &st : path) {
613 fileSize += GetDiskUsage(st);
614 }
615 return fileSize;
616 }
617
ScanDir(const std::string & dirPath,ScanMode scanMode,ResultMode resultMode,std::vector<std::string> & paths)618 bool InstalldOperator::ScanDir(
619 const std::string &dirPath, ScanMode scanMode, ResultMode resultMode, std::vector<std::string> &paths)
620 {
621 if (dirPath.empty() || (dirPath.size() > Constants::PATH_MAX_SIZE)) {
622 APP_LOGE("Scan dir path invaild");
623 return false;
624 }
625
626 std::string realPath = "";
627 if (!PathToRealPath(dirPath, realPath)) {
628 APP_LOGE("file(%{public}s) is not real path", dirPath.c_str());
629 return false;
630 }
631
632 DIR* dir = opendir(realPath.c_str());
633 if (dir == nullptr) {
634 APP_LOGE("Scan open dir(%{public}s) fail", realPath.c_str());
635 return false;
636 }
637
638 struct dirent *ptr = nullptr;
639 while ((ptr = readdir(dir)) != nullptr) {
640 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
641 continue;
642 }
643
644 std::string subName(ptr->d_name);
645 if (scanMode == ScanMode::SUB_FILE_DIR) {
646 if (ptr->d_type == DT_DIR) {
647 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
648 }
649
650 continue;
651 }
652
653 if (scanMode == ScanMode::SUB_FILE_FILE) {
654 if (ptr->d_type == DT_REG) {
655 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
656 }
657
658 continue;
659 }
660
661 paths.emplace_back(HandleScanResult(dirPath, subName, resultMode));
662 }
663
664 closedir(dir);
665 return true;
666 }
667
CopyFile(const std::string & sourceFile,const std::string & destinationFile)668 bool InstalldOperator::CopyFile(
669 const std::string &sourceFile, const std::string &destinationFile)
670 {
671 if (sourceFile.empty() || destinationFile.empty()) {
672 APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
673 return false;
674 }
675
676 std::ifstream in(sourceFile);
677 if (!in.is_open()) {
678 APP_LOGE("Copy file failed due to open sourceFile failed");
679 return false;
680 }
681
682 std::ofstream out(destinationFile);
683 if (!out.is_open()) {
684 APP_LOGE("Copy file failed due to open destinationFile failed");
685 in.close();
686 return false;
687 }
688
689 out << in.rdbuf();
690 in.close();
691 out.close();
692 return true;
693 }
694
ExtractDiffFiles(const std::string & filePath,const std::string & targetPath,const std::string & cpuAbi)695 bool InstalldOperator::ExtractDiffFiles(const std::string &filePath, const std::string &targetPath,
696 const std::string &cpuAbi)
697 {
698 BundleExtractor extractor(filePath);
699 if (!extractor.Init()) {
700 return false;
701 }
702 std::vector<std::string> entryNames;
703 if (!extractor.GetZipFileNames(entryNames)) {
704 return false;
705 }
706 for (const auto &entryName : entryNames) {
707 if (strcmp(entryName.c_str(), ".") == 0 ||
708 strcmp(entryName.c_str(), "..") == 0) {
709 continue;
710 }
711 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
712 continue;
713 }
714 // handle diff file
715 if (IsDiffFiles(entryName, targetPath, cpuAbi)) {
716 ExtractTargetFile(extractor, entryName, targetPath, cpuAbi);
717 }
718 }
719 return true;
720 }
721
OpenHandle(void ** handle)722 bool InstalldOperator::OpenHandle(void **handle)
723 {
724 APP_LOGI("InstalldOperator::OpenHandle start");
725 if (handle == nullptr) {
726 APP_LOGE("InstalldOperator::OpenHandle error handle is nullptr.");
727 return false;
728 }
729 if (IsExistDir(Constants::SYSTEM_LIB64)) {
730 *handle = dlopen(LIB64_DIFF_PATCH_SHARED_SO_PATH, RTLD_NOW | RTLD_GLOBAL);
731 } else {
732 *handle = dlopen(LIB_DIFF_PATCH_SHARED_SO_PATH, RTLD_NOW | RTLD_GLOBAL);
733 }
734 if (*handle == nullptr) {
735 APP_LOGE("ApplyDiffPatch failed to open libdiff_patch_shared.z.so, err:%{public}s", dlerror());
736 return false;
737 }
738 APP_LOGI("InstalldOperator::OpenHandle end");
739 return true;
740 }
741
CloseHandle(void ** handle)742 void InstalldOperator::CloseHandle(void **handle)
743 {
744 APP_LOGI("InstalldOperator::CloseHandle start");
745 if ((handle != nullptr) && (*handle != nullptr)) {
746 dlclose(*handle);
747 *handle = nullptr;
748 APP_LOGD("InstalldOperator::CloseHandle, err:%{public}s", dlerror());
749 }
750 APP_LOGI("InstalldOperator::CloseHandle end");
751 }
752
ProcessApplyDiffPatchPath(const std::string & oldSoPath,const std::string & diffFilePath,const std::string & newSoPath,std::vector<std::string> & oldSoFileNames,std::vector<std::string> & diffFileNames)753 bool InstalldOperator::ProcessApplyDiffPatchPath(
754 const std::string &oldSoPath, const std::string &diffFilePath,
755 const std::string &newSoPath, std::vector<std::string> &oldSoFileNames, std::vector<std::string> &diffFileNames)
756 {
757 APP_LOGI("ProcessApplyDiffPatchPath oldSoPath: %{private}s, diffFilePath: %{private}s, newSoPath: %{public}s",
758 oldSoPath.c_str(), diffFilePath.c_str(), newSoPath.c_str());
759 if (oldSoPath.empty() || diffFilePath.empty() || newSoPath.empty()) {
760 return false;
761 }
762 if (!IsExistDir(oldSoPath) || !IsExistDir(diffFilePath)) {
763 APP_LOGE("ProcessApplyDiffPatchPath oldSoPath or diffFilePath not exist");
764 return false;
765 }
766
767 if (!ScanDir(oldSoPath, ScanMode::SUB_FILE_FILE, ResultMode::RELATIVE_PATH, oldSoFileNames)) {
768 APP_LOGE("ProcessApplyDiffPatchPath ScanDir oldSoPath failed");
769 return false;
770 }
771
772 if (!ScanDir(diffFilePath, ScanMode::SUB_FILE_FILE, ResultMode::RELATIVE_PATH, diffFileNames)) {
773 APP_LOGE("ProcessApplyDiffPatchPath ScanDir diffFilePath failed");
774 return false;
775 }
776
777 if (oldSoFileNames.empty() || diffFileNames.empty()) {
778 APP_LOGE("ProcessApplyDiffPatchPath so or diff files empty");
779 return false;
780 }
781
782 if (!IsExistDir(newSoPath)) {
783 APP_LOGD("ProcessApplyDiffPatchPath create newSoPath");
784 if (!MkRecursiveDir(newSoPath, true)) {
785 APP_LOGE("ProcessApplyDiffPatchPath create newSo dir (%{private}s) failed", newSoPath.c_str());
786 return false;
787 }
788 }
789 APP_LOGI("ProcessApplyDiffPatchPath end");
790 return true;
791 }
792
ApplyDiffPatch(const std::string & oldSoPath,const std::string & diffFilePath,const std::string & newSoPath)793 bool InstalldOperator::ApplyDiffPatch(const std::string &oldSoPath, const std::string &diffFilePath,
794 const std::string &newSoPath)
795 {
796 APP_LOGI("ApplyDiffPatch start");
797 std::vector<std::string> oldSoFileNames;
798 std::vector<std::string> diffFileNames;
799 if (InstalldOperator::IsDirEmpty(oldSoPath) || InstalldOperator::IsDirEmpty(diffFilePath)) {
800 APP_LOGD("oldSoPath or diffFilePath is empty, not require ApplyPatch");
801 return true;
802 }
803 if (!ProcessApplyDiffPatchPath(oldSoPath, diffFilePath, newSoPath, oldSoFileNames, diffFileNames)) {
804 APP_LOGE("ApplyDiffPatch ProcessApplyDiffPatchPath failed");
805 return false;
806 }
807 std::string realOldSoPath;
808 std::string realDiffFilePath;
809 std::string realNewSoPath;
810 if (!PathToRealPath(oldSoPath, realOldSoPath) || !PathToRealPath(diffFilePath, realDiffFilePath) ||
811 !PathToRealPath(newSoPath, realNewSoPath)) {
812 APP_LOGE("ApplyDiffPatch Path is not real path");
813 return false;
814 }
815 void *handle = nullptr;
816 if (!OpenHandle(&handle)) {
817 return false;
818 }
819 auto applyPatch = reinterpret_cast<ApplyPatch>(dlsym(handle, APPLY_PATCH_FUNCTION_NAME));
820 if (applyPatch == nullptr) {
821 APP_LOGE("ApplyDiffPatch failed to get applyPatch err:%{public}s", dlerror());
822 CloseHandle(&handle);
823 return false;
824 }
825 std::vector<std::string> newSoList;
826 for (const auto &diffFileName : diffFileNames) {
827 std::string soFileName = diffFileName.substr(0, diffFileName.rfind(Constants::DIFF_SUFFIX));
828 APP_LOGD("ApplyDiffPatch soName: %{public}s, diffName: %{public}s", soFileName.c_str(), diffFileName.c_str());
829 if (find(oldSoFileNames.begin(), oldSoFileNames.end(), soFileName) != oldSoFileNames.end()) {
830 int32_t ret = applyPatch(realDiffFilePath + Constants::PATH_SEPARATOR + diffFileName,
831 realOldSoPath + Constants::PATH_SEPARATOR + soFileName,
832 realNewSoPath + Constants::PATH_SEPARATOR + soFileName);
833 if (ret != ERR_OK) {
834 APP_LOGE("ApplyDiffPatch failed, applyPatch errcode: %{public}d", ret);
835 for (const auto &file : newSoList) {
836 DeleteDir(file);
837 }
838 CloseHandle(&handle);
839 return false;
840 }
841 newSoList.emplace_back(realNewSoPath + Constants::PATH_SEPARATOR + soFileName);
842 }
843 }
844 CloseHandle(&handle);
845 APP_LOGI("ApplyDiffPatch end");
846 return true;
847 }
848
ObtainQuickFixFileDir(const std::string & dir,std::vector<std::string> & fileVec)849 bool InstalldOperator::ObtainQuickFixFileDir(const std::string &dir, std::vector<std::string> &fileVec)
850 {
851 if (dir.empty()) {
852 APP_LOGE("ObtainQuickFixFileDir dir path invaild");
853 return false;
854 }
855
856 std::string realPath = "";
857 if (!PathToRealPath(dir, realPath)) {
858 APP_LOGE("dir(%{public}s) is not real path", dir.c_str());
859 return false;
860 }
861
862 DIR* directory = opendir(realPath.c_str());
863 if (directory == nullptr) {
864 APP_LOGE("ObtainQuickFixFileDir open dir(%{public}s) fail", realPath.c_str());
865 return false;
866 }
867
868 struct dirent *ptr = nullptr;
869 while ((ptr = readdir(directory)) != nullptr) {
870 std::string currentName(ptr->d_name);
871 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
872 continue;
873 }
874
875 std::string curPath = dir + Constants::PATH_SEPARATOR + currentName;
876 struct stat s;
877 if (stat(curPath.c_str(), &s) == 0) {
878 // directory
879 if (s.st_mode & S_IFDIR) {
880 ObtainQuickFixFileDir(curPath, fileVec);
881 }
882
883 // file
884 if ((s.st_mode & S_IFREG) &&
885 (currentName.find(Constants::QUICK_FIX_FILE_SUFFIX) != std::string::npos)) {
886 fileVec.emplace_back(dir);
887 }
888 }
889 }
890 closedir(directory);
891 return true;
892 }
893
CopyFiles(const std::string & sourceDir,const std::string & destinationDir)894 bool InstalldOperator::CopyFiles(const std::string &sourceDir, const std::string &destinationDir)
895 {
896 APP_LOGD("sourceDir is %{public}s, destinationDir is %{public}s", sourceDir.c_str(), destinationDir.c_str());
897 if (sourceDir.empty() || destinationDir.empty()) {
898 APP_LOGE("Copy file failed due to sourceDir or destinationDir is empty");
899 return false;
900 }
901
902 std::string realPath = "";
903 if (!PathToRealPath(sourceDir, realPath)) {
904 APP_LOGE("sourceDir(%{public}s) is not real path", sourceDir.c_str());
905 return false;
906 }
907
908 DIR* directory = opendir(realPath.c_str());
909 if (directory == nullptr) {
910 APP_LOGE("CopyFiles open dir(%{public}s) fail", realPath.c_str());
911 return false;
912 }
913
914 struct dirent *ptr = nullptr;
915 while ((ptr = readdir(directory)) != nullptr) {
916 std::string currentName(ptr->d_name);
917 if (currentName.compare(".") == 0 || currentName.compare("..") == 0) {
918 continue;
919 }
920
921 std::string curPath = sourceDir + Constants::PATH_SEPARATOR + currentName;
922 struct stat s;
923 if ((stat(curPath.c_str(), &s) == 0) && (s.st_mode & S_IFREG)) {
924 std::string innerDesStr = destinationDir + Constants::PATH_SEPARATOR + currentName;
925 if (CopyFile(curPath, innerDesStr)) {
926 ChangeFileAttr(innerDesStr, Constants::FOUNDATION_UID, Constants::BMS_GID);
927 }
928 }
929 }
930 closedir(directory);
931 return true;
932 }
933 } // namespace AppExecFwk
934 } // namespace OHOS