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