• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &currentPath, 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