1 /*
2  * Copyright (c) 2021-2024 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 "bundle_util.h"
17 
18 #include <cinttypes>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <fstream>
22 #include <sstream>
23 #include <sys/sendfile.h>
24 #include <sys/statfs.h>
25 
26 #include "bundle_service_constants.h"
27 #ifdef CONFIG_POLOCY_ENABLE
28 #include "config_policy_utils.h"
29 #endif
30 #include "directory_ex.h"
31 #include "hitrace_meter.h"
32 #include "installd_client.h"
33 #include "ipc_skeleton.h"
34 #include "parameter.h"
35 #include "string_ex.h"
36 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
37 #include "type_descriptor.h"
38 #include "utd_client.h"
39 #endif
40 
41 namespace OHOS {
42 namespace AppExecFwk {
43 namespace {
44 const std::string::size_type EXPECT_SPLIT_SIZE = 2;
45 const size_t ORIGIN_STRING_LENGTH = 32;
46 constexpr char UUID_SEPARATOR = '-';
47 const std::vector<int32_t> SEPARATOR_POSITIONS { 8, 13, 18, 23};
48 const int64_t HALF_GB = 1024 * 1024 * 512; // 0.5GB
49 const int64_t SPACE_NEED_DOUBLE = 2;
50 const uint32_t UUID_LENGTH_MAX = 512;
51 static std::string g_deviceUdid;
52 static std::mutex g_mutex;
53 // hmdfs and sharefs config
54 constexpr const char* BUNDLE_ID_FILE = "appid";
55 // single max hap size
56 constexpr int64_t ONE_GB = 1024 * 1024 * 1024;
57 constexpr int64_t MAX_HAP_SIZE = ONE_GB * 4;  // 4GB
58 constexpr const char* ABC_FILE_PATH = "abc_files";
59 constexpr const char* PGO_FILE_PATH = "pgo_files";
60 const std::string EMPTY_STRING = "";
61 constexpr int64_t DISK_REMAINING_SIZE_LIMIT = 1024 * 1024 * 10; // 10M
62 #ifdef CONFIG_POLOCY_ENABLE
63     const char* NO_DISABLING_CONFIG_PATH = "/etc/ability_runtime/resident_process_in_extreme_memory.json";
64 #endif
65 const char* NO_DISABLING_CONFIG_PATH_DEFAULT =
66     "/system/etc/ability_runtime/resident_process_in_extreme_memory.json";
67 }
68 
69 std::mutex BundleUtil::g_mutex;
70 
CheckFilePath(const std::string & bundlePath,std::string & realPath)71 ErrCode BundleUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
72 {
73     if (!CheckFileName(bundlePath)) {
74         APP_LOGE("bundle file path invalid");
75         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
76     }
77     if (!CheckFileType(bundlePath, ServiceConstants::INSTALL_FILE_SUFFIX) &&
78         !CheckFileType(bundlePath, ServiceConstants::HSP_FILE_SUFFIX) &&
79         !CheckFileType(bundlePath, ServiceConstants::QUICK_FIX_FILE_SUFFIX) &&
80         !CheckFileType(bundlePath, ServiceConstants::CODE_SIGNATURE_FILE_SUFFIX)) {
81         APP_LOGE("file is not hap, hsp, hqf or sig");
82         return ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME;
83     }
84     if (!PathToRealPath(bundlePath, realPath)) {
85         APP_LOGE("file is not real path");
86         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
87     }
88     if (access(realPath.c_str(), F_OK) != 0) {
89         APP_LOGE("not access the bundle file path: %{public}s, errno:%{public}d", realPath.c_str(), errno);
90         return ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE;
91     }
92     if (!CheckFileSize(realPath, MAX_HAP_SIZE)) {
93         APP_LOGE("file size larger than max hap size Max size is: %{public}" PRId64, MAX_HAP_SIZE);
94         return ERR_APPEXECFWK_INSTALL_INVALID_HAP_SIZE;
95     }
96     return ERR_OK;
97 }
98 
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)99 ErrCode BundleUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
100 {
101     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
102     // there are three cases for bundlePaths:
103     // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
104     // 2. one hap direction in the bundlePaths.
105     // 3. some hap file directions in the bundlePaths.
106     APP_LOGD("check file path");
107     if (bundlePaths.empty()) {
108         APP_LOGE("bundle file paths invalid");
109         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
110     }
111     ErrCode ret = ERR_OK;
112 
113     if (bundlePaths.size() == 1) {
114         struct stat s;
115         std::string bundlePath = bundlePaths.front();
116         if (stat(bundlePath.c_str(), &s) == 0) {
117             std::string realPath = "";
118             // it is a direction
119             if ((s.st_mode & S_IFDIR) && !GetHapFilesFromBundlePath(bundlePath, realPaths)) {
120                 APP_LOGE("GetHapFilesFromBundlePath failed with bundlePath:%{public}s", bundlePaths.front().c_str());
121                 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
122             }
123             // it is a file
124             if ((s.st_mode & S_IFREG) && (ret = CheckFilePath(bundlePaths.front(), realPath)) == ERR_OK) {
125                 realPaths.emplace_back(realPath);
126             }
127             return ret;
128         } else {
129             APP_LOGE("bundlePath not existed with :%{public}s errno %{public}d", bundlePaths.front().c_str(), errno);
130             return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
131         }
132     } else {
133         for (const std::string& bundlePath : bundlePaths) {
134             std::string realPath = "";
135             ret = CheckFilePath(bundlePath, realPath);
136             if (ret != ERR_OK) {
137                 return ret;
138             }
139             realPaths.emplace_back(realPath);
140         }
141     }
142     APP_LOGD("finish check file path");
143     return ret;
144 }
145 
CheckFileType(const std::string & fileName,const std::string & extensionName)146 bool BundleUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
147 {
148     APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
149     if (!CheckFileName(fileName)) {
150         return false;
151     }
152 
153     auto position = fileName.rfind('.');
154     if (position == std::string::npos) {
155         APP_LOGE("filename no extension name");
156         return false;
157     }
158 
159     std::string suffixStr = fileName.substr(position);
160     return LowerStr(suffixStr) == extensionName;
161 }
162 
CheckFileName(const std::string & fileName)163 bool BundleUtil::CheckFileName(const std::string &fileName)
164 {
165     if (fileName.empty()) {
166         APP_LOGE("the file name is empty");
167         return false;
168     }
169     if (fileName.size() > ServiceConstants::PATH_MAX_SIZE) {
170         APP_LOGE("bundle file path length %{public}zu too long", fileName.size());
171         return false;
172     }
173     return true;
174 }
175 
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)176 bool BundleUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
177 {
178     APP_LOGD("fileSize is %{public}" PRId64, fileSize);
179     struct stat fileInfo = { 0 };
180     if (stat(bundlePath.c_str(), &fileInfo) != 0) {
181         APP_LOGE("call stat error:%{public}d", errno);
182         return false;
183     }
184     if (fileInfo.st_size > fileSize) {
185         return false;
186     }
187     return true;
188 }
189 
CheckSystemSize(const std::string & bundlePath,const std::string & diskPath)190 bool BundleUtil::CheckSystemSize(const std::string &bundlePath, const std::string &diskPath)
191 {
192     struct statfs diskInfo = { 0 };
193     if (statfs(diskPath.c_str(), &diskInfo) != 0) {
194         APP_LOGE("call statfs error:%{public}d", errno);
195         return false;
196     }
197     int64_t freeSize = static_cast<int64_t>(diskInfo.f_bavail * diskInfo.f_bsize);
198     APP_LOGD("left free size in the disk path is %{public}" PRId64, freeSize);
199     struct stat fileInfo = { 0 };
200     if (stat(bundlePath.c_str(), &fileInfo) != 0) {
201         APP_LOGE("call stat error:%{public}d", errno);
202         return false;
203     }
204     if (std::max(fileInfo.st_size * SPACE_NEED_DOUBLE, HALF_GB) > freeSize) {
205         return false;
206     }
207     return true;
208 }
209 
CheckSystemFreeSize(const std::string & path,int64_t size)210 bool BundleUtil::CheckSystemFreeSize(const std::string &path, int64_t size)
211 {
212     struct statfs diskInfo = { 0 };
213     if (statfs(path.c_str(), &diskInfo) != 0) {
214         APP_LOGE("call statfs error:%{public}d", errno);
215         return false;
216     }
217     int64_t freeSize = static_cast<int64_t>(diskInfo.f_bavail * diskInfo.f_bsize);
218     return freeSize >= size;
219 }
220 
CheckSystemSizeAndHisysEvent(const std::string & path,const std::string & fileName)221 bool BundleUtil::CheckSystemSizeAndHisysEvent(const std::string &path, const std::string &fileName)
222 {
223     struct statfs diskInfo = { 0 };
224     if (statfs(path.c_str(), &diskInfo) != 0) {
225         APP_LOGE("call statfs error:%{public}d", errno);
226         return false;
227     }
228     int64_t freeSize = static_cast<int64_t>(diskInfo.f_bavail * diskInfo.f_bsize);
229     return freeSize < DISK_REMAINING_SIZE_LIMIT;
230 }
231 
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)232 bool BundleUtil::GetHapFilesFromBundlePath(const std::string& currentBundlePath, std::vector<std::string>& hapFileList)
233 {
234     APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
235     if (currentBundlePath.empty()) {
236         return false;
237     }
238     DIR* dir = opendir(currentBundlePath.c_str());
239     if (dir == nullptr) {
240         char errMsg[256] = {0};
241         strerror_r(errno, errMsg, sizeof(errMsg));
242         APP_LOGE("GetHapFilesFromBundlePath open bundle dir:%{public}s failed due to %{public}s, errno:%{public}d",
243             currentBundlePath.c_str(), errMsg, errno);
244         return false;
245     }
246     std::string bundlePath = currentBundlePath;
247     if (bundlePath.back() != ServiceConstants::FILE_SEPARATOR_CHAR) {
248         bundlePath.append(ServiceConstants::PATH_SEPARATOR);
249     }
250     struct dirent *entry = nullptr;
251     while ((entry = readdir(dir)) != nullptr) {
252         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
253             continue;
254         }
255         const std::string hapFilePath = bundlePath + entry->d_name;
256         std::string realPath = "";
257         if (CheckFilePath(hapFilePath, realPath) != ERR_OK) {
258             APP_LOGE("find invalid hap path %{public}s", hapFilePath.c_str());
259             closedir(dir);
260             return false;
261         }
262         hapFileList.emplace_back(realPath);
263         APP_LOGD("find hap path %{public}s", realPath.c_str());
264 
265         if (!hapFileList.empty() && (hapFileList.size() > ServiceConstants::MAX_HAP_NUMBER)) {
266             APP_LOGE("reach the max hap number 128, stop to add more");
267             closedir(dir);
268             return false;
269         }
270     }
271     closedir(dir);
272     return true;
273 }
274 
GetCurrentTime()275 int64_t BundleUtil::GetCurrentTime()
276 {
277     int64_t time =
278         std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
279         .count();
280     APP_LOGD("the current time in seconds is %{public}" PRId64, time);
281     return time;
282 }
283 
GetCurrentTimeMs()284 int64_t BundleUtil::GetCurrentTimeMs()
285 {
286     int64_t time =
287         std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
288         .count();
289     APP_LOGD("the current time in milliseconds is %{public}" PRId64, time);
290     return time;
291 }
292 
GetCurrentTimeNs()293 int64_t BundleUtil::GetCurrentTimeNs()
294 {
295     int64_t time =
296         std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
297         .count();
298     APP_LOGD("the current time in nanoseconds is %{public}" PRId64, time);
299     return time;
300 }
301 
DeviceAndNameToKey(const std::string & deviceId,const std::string & bundleName,std::string & key)302 void BundleUtil::DeviceAndNameToKey(
303     const std::string &deviceId, const std::string &bundleName, std::string &key)
304 {
305     key.append(deviceId);
306     key.append(Constants::FILE_UNDERLINE);
307     key.append(bundleName);
308     APP_LOGD("bundleName = %{public}s", bundleName.c_str());
309 }
310 
KeyToDeviceAndName(const std::string & key,std::string & deviceId,std::string & bundleName)311 bool BundleUtil::KeyToDeviceAndName(
312     const std::string &key, std::string &deviceId, std::string &bundleName)
313 {
314     bool ret = false;
315     std::vector<std::string> splitStrs;
316     OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs);
317     // the expect split size should be 2.
318     // key rule is <deviceId>_<bundleName>
319     if (splitStrs.size() == EXPECT_SPLIT_SIZE) {
320         deviceId = splitStrs[0];
321         bundleName = splitStrs[1];
322         ret = true;
323     }
324     APP_LOGD("bundleName = %{public}s", bundleName.c_str());
325     return ret;
326 }
327 
GetUserIdByCallingUid()328 int32_t BundleUtil::GetUserIdByCallingUid()
329 {
330     int32_t uid = IPCSkeleton::GetCallingUid();
331     APP_LOGD("get calling uid(%{public}d)", uid);
332     return GetUserIdByUid(uid);
333 }
334 
GetUserIdByUid(int32_t uid)335 int32_t BundleUtil::GetUserIdByUid(int32_t uid)
336 {
337     if (uid <= Constants::INVALID_UID) {
338         APP_LOGE("uid illegal: %{public}d", uid);
339         return Constants::INVALID_USERID;
340     }
341 
342     return uid / Constants::BASE_USER_RANGE;
343 }
344 
MakeFsConfig(const std::string & bundleName,int32_t bundleId,const std::string & configPath)345 void BundleUtil::MakeFsConfig(const std::string &bundleName, int32_t bundleId, const std::string &configPath)
346 {
347     std::string bundleDir = configPath + ServiceConstants::PATH_SEPARATOR + bundleName;
348     if (access(bundleDir.c_str(), F_OK) != 0) {
349         APP_LOGD("fail to access error:%{public}d", errno);
350         if (mkdir(bundleDir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
351             APP_LOGE("make bundle dir error:%{public}d", errno);
352             return;
353         }
354     }
355 
356     std::string realBundleDir;
357     if (!PathToRealPath(bundleDir, realBundleDir)) {
358         APP_LOGE("bundleIdFile is not real path");
359         return;
360     }
361 
362     realBundleDir += (ServiceConstants::PATH_SEPARATOR + BUNDLE_ID_FILE);
363 
364     int32_t bundleIdFd = open(realBundleDir.c_str(), O_WRONLY | O_TRUNC);
365     if (bundleIdFd > 0) {
366         std::string bundleIdStr = std::to_string(bundleId);
367         if (write(bundleIdFd, bundleIdStr.c_str(), bundleIdStr.size()) < 0) {
368             APP_LOGE("write bundleId error:%{public}d", errno);
369         }
370     }
371     close(bundleIdFd);
372 }
373 
RemoveFsConfig(const std::string & bundleName,const std::string & configPath)374 void BundleUtil::RemoveFsConfig(const std::string &bundleName, const std::string &configPath)
375 {
376     std::string bundleDir = configPath + ServiceConstants::PATH_SEPARATOR + bundleName;
377     std::string realBundleDir;
378     if (!PathToRealPath(bundleDir, realBundleDir)) {
379         APP_LOGE("bundleDir is not real path");
380         return;
381     }
382     if (rmdir(realBundleDir.c_str()) != 0) {
383         APP_LOGE("remove hmdfs bundle dir error:%{public}d", errno);
384     }
385 }
386 
CreateTempDir(const std::string & tempDir)387 std::string BundleUtil::CreateTempDir(const std::string &tempDir)
388 {
389     if (!OHOS::ForceCreateDirectory(tempDir)) {
390         APP_LOGE("mkdir %{public}s failed", tempDir.c_str());
391         return "";
392     }
393     if (chown(tempDir.c_str(), Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != 0) {
394         APP_LOGE("fail to change %{public}s ownership errno:%{public}d", tempDir.c_str(), errno);
395         return "";
396     }
397     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
398     if (!OHOS::ChangeModeFile(tempDir, mode)) {
399         APP_LOGE("change mode failed, temp install dir : %{public}s", tempDir.c_str());
400         return "";
401     }
402     return tempDir;
403 }
404 
CreateInstallTempDir(uint32_t installerId,const DirType & type)405 std::string BundleUtil::CreateInstallTempDir(uint32_t installerId, const DirType &type)
406 {
407     std::time_t curTime = std::time(0);
408     std::string tempDir = ServiceConstants::HAP_COPY_PATH;
409     if (type == DirType::STREAM_INSTALL_DIR) {
410         tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::STREAM_INSTALL_PATH;
411     } else if (type == DirType::QUICK_FIX_DIR) {
412         tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::QUICK_FIX_PATH;
413     } else if (type == DirType::SIG_FILE_DIR) {
414         tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::SIGNATURE_FILE_PATH;
415     } else if (type == DirType::PGO_FILE_DIR) {
416         tempDir += ServiceConstants::PATH_SEPARATOR + PGO_FILE_PATH;
417     } else if (type == DirType::ABC_FILE_DIR) {
418         tempDir += ServiceConstants::PATH_SEPARATOR + ABC_FILE_PATH;
419     } else if (type == DirType::EXT_RESOURCE_FILE_DIR) {
420         tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::EXT_RESOURCE_FILE_PATH;
421     } else {
422         return "";
423     }
424 
425     if (CreateTempDir(tempDir).empty()) {
426         APP_LOGE("create tempDir failed");
427         return "";
428     }
429 
430     tempDir += ServiceConstants::PATH_SEPARATOR + std::to_string(curTime) +
431         std::to_string(installerId) + ServiceConstants::PATH_SEPARATOR;
432     return CreateTempDir(tempDir);
433 }
434 
CreateSharedBundleTempDir(uint32_t installerId,uint32_t index)435 std::string BundleUtil::CreateSharedBundleTempDir(uint32_t installerId, uint32_t index)
436 {
437     std::time_t curTime = std::time(0);
438     std::string tempDir = ServiceConstants::HAP_COPY_PATH;
439     tempDir += ServiceConstants::PATH_SEPARATOR + ServiceConstants::STREAM_INSTALL_PATH;
440     tempDir += ServiceConstants::PATH_SEPARATOR + std::to_string(curTime) + std::to_string(installerId)
441         + Constants::FILE_UNDERLINE + std::to_string(index)+ ServiceConstants::PATH_SEPARATOR;
442     return CreateTempDir(tempDir);
443 }
444 
CreateFileDescriptor(const std::string & bundlePath,long long offset)445 int32_t BundleUtil::CreateFileDescriptor(const std::string &bundlePath, long long offset)
446 {
447     int fd = -1;
448     if (bundlePath.length() > ServiceConstants::PATH_MAX_SIZE) {
449         APP_LOGE("the length of the bundlePath exceeds maximum limitation");
450         return fd;
451     }
452     if ((fd = open(bundlePath.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
453         APP_LOGE("open bundlePath %{public}s failed errno:%{public}d", bundlePath.c_str(), errno);
454         return fd;
455     }
456     if (offset > 0) {
457         lseek(fd, offset, SEEK_SET);
458     }
459     return fd;
460 }
461 
CreateFileDescriptorForReadOnly(const std::string & bundlePath,long long offset)462 int32_t BundleUtil::CreateFileDescriptorForReadOnly(const std::string &bundlePath, long long offset)
463 {
464     int fd = -1;
465     if (bundlePath.length() > ServiceConstants::PATH_MAX_SIZE) {
466         APP_LOGE("the length of the bundlePath exceeds maximum limitation");
467         return fd;
468     }
469     std::string realPath;
470     if (!PathToRealPath(bundlePath, realPath)) {
471         APP_LOGE("file is not real path");
472         return fd;
473     }
474 
475     if ((fd = open(realPath.c_str(), O_RDONLY)) < 0) {
476         APP_LOGE("open bundlePath %{public}s failed errno:%{public}d", realPath.c_str(), errno);
477         return fd;
478     }
479     if (offset > 0) {
480         lseek(fd, offset, SEEK_SET);
481     }
482     return fd;
483 }
484 
CloseFileDescriptor(std::vector<int32_t> & fdVec)485 void BundleUtil::CloseFileDescriptor(std::vector<int32_t> &fdVec)
486 {
487     for_each(fdVec.begin(), fdVec.end(), [](const auto &fd) {
488         if (fd > 0) {
489             close(fd);
490         }
491     });
492     fdVec.clear();
493 }
494 
IsExistFile(const std::string & path)495 bool BundleUtil::IsExistFile(const std::string &path)
496 {
497     if (path.empty()) {
498         return false;
499     }
500 
501     struct stat buf = {};
502     if (stat(path.c_str(), &buf) != 0) {
503         APP_LOGE("fail stat errno:%{public}d", errno);
504         return false;
505     }
506 
507     return S_ISREG(buf.st_mode);
508 }
509 
IsExistFileNoLog(const std::string & path)510 bool BundleUtil::IsExistFileNoLog(const std::string &path)
511 {
512     if (path.empty()) {
513         return false;
514     }
515 
516     struct stat buf = {};
517     if (stat(path.c_str(), &buf) != 0) {
518         return false;
519     }
520 
521     return S_ISREG(buf.st_mode);
522 }
523 
IsExistDir(const std::string & path)524 bool BundleUtil::IsExistDir(const std::string &path)
525 {
526     if (path.empty()) {
527         return false;
528     }
529 
530     struct stat buf = {};
531     if (stat(path.c_str(), &buf) != 0) {
532         APP_LOGE("fail stat errno:%{public}d", errno);
533         return false;
534     }
535 
536     return S_ISDIR(buf.st_mode);
537 }
538 
IsExistDirNoLog(const std::string & path)539 bool BundleUtil::IsExistDirNoLog(const std::string &path)
540 {
541     if (path.empty()) {
542         return false;
543     }
544 
545     struct stat buf = {};
546     if (stat(path.c_str(), &buf) != 0) {
547         return false;
548     }
549 
550     return S_ISDIR(buf.st_mode);
551 }
552 
IsPathInformationConsistent(const std::string & path,int32_t uid,int32_t gid)553 bool BundleUtil::IsPathInformationConsistent(const std::string &path, int32_t uid, int32_t gid)
554 {
555     if (path.empty()) {
556         return false;
557     }
558     struct stat buf = {};
559     if (stat(path.c_str(), &buf) != 0) {
560         return false;
561     }
562     if ((static_cast<int32_t>(buf.st_uid) != uid) || ((static_cast<int32_t>(buf.st_gid) != gid))) {
563         APP_LOGE("path uid or gid is not same");
564         return false;
565     }
566     return true;
567 }
568 
CalculateFileSize(const std::string & bundlePath)569 int64_t BundleUtil::CalculateFileSize(const std::string &bundlePath)
570 {
571     struct stat fileInfo = { 0 };
572     if (stat(bundlePath.c_str(), &fileInfo) != 0) {
573         APP_LOGE("call stat error:%{public}d", errno);
574         return 0;
575     }
576 
577     return static_cast<int64_t>(fileInfo.st_size);
578 }
579 
RenameFile(const std::string & oldPath,const std::string & newPath)580 bool BundleUtil::RenameFile(const std::string &oldPath, const std::string &newPath)
581 {
582     if (oldPath.empty() || newPath.empty()) {
583         APP_LOGE("oldPath or newPath is empty");
584         return false;
585     }
586 
587     if (!DeleteDir(newPath)) {
588         APP_LOGE("delete newPath failed");
589         return false;
590     }
591 
592     return rename(oldPath.c_str(), newPath.c_str()) == 0;
593 }
594 
DeleteDir(const std::string & path)595 bool BundleUtil::DeleteDir(const std::string &path)
596 {
597     if (IsExistFile(path)) {
598         return OHOS::RemoveFile(path);
599     }
600 
601     if (IsExistDir(path)) {
602         return OHOS::ForceRemoveDirectory(path);
603     }
604 
605     return true;
606 }
607 
IsUtd(const std::string & param)608 bool BundleUtil::IsUtd(const std::string &param)
609 {
610 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
611     bool isUtd = false;
612     auto ret = UDMF::UtdClient::GetInstance().IsUtd(param, isUtd);
613     return ret == ERR_OK && isUtd;
614 #else
615     return false;
616 #endif
617 }
618 
IsSpecificUtd(const std::string & param)619 bool BundleUtil::IsSpecificUtd(const std::string &param)
620 {
621     if (!IsUtd(param)) {
622         return false;
623     }
624 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
625     std::shared_ptr<UDMF::TypeDescriptor> typeDescriptor;
626     auto ret = UDMF::UtdClient::GetInstance().GetTypeDescriptor(param, typeDescriptor);
627     if (ret != ERR_OK || typeDescriptor == nullptr) {
628         return false;
629     }
630     std::vector<std::string> mimeTypes = typeDescriptor->GetMimeTypes();
631     std::vector<std::string> filenameExtensions = typeDescriptor->GetFilenameExtensions();
632     return !mimeTypes.empty() || !filenameExtensions.empty();
633 #else
634     return false;
635 #endif
636 }
637 
GetUtdVectorByMimeType(const std::string & mimeType)638 std::vector<std::string> BundleUtil::GetUtdVectorByMimeType(const std::string &mimeType)
639 {
640 #ifdef BUNDLE_FRAMEWORK_UDMF_ENABLED
641     std::vector<std::string> utdVector;
642     auto ret = UDMF::UtdClient::GetInstance().GetUniformDataTypesByMIMEType(mimeType, utdVector);
643     if (ret != ERR_OK || utdVector.empty()) {
644         return {};
645     }
646     return utdVector;
647 #else
648     return {};
649 #endif
650 }
651 
GetBoolStrVal(bool val)652 std::string BundleUtil::GetBoolStrVal(bool val)
653 {
654     return val ? "true" : "false";
655 }
656 
CopyFile(const std::string & sourceFile,const std::string & destinationFile)657 bool BundleUtil::CopyFile(
658     const std::string &sourceFile, const std::string &destinationFile)
659 {
660     if (sourceFile.empty() || destinationFile.empty()) {
661         APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
662         return false;
663     }
664 
665     std::ifstream in(sourceFile);
666     if (!in.is_open()) {
667         APP_LOGE("Copy file failed due to open sourceFile failed errno:%{public}d", errno);
668         return false;
669     }
670 
671     std::ofstream out(destinationFile);
672     if (!out.is_open()) {
673         APP_LOGE("Copy file failed due to open destinationFile failed errno:%{public}d", errno);
674         in.close();
675         return false;
676     }
677 
678     out << in.rdbuf();
679     in.close();
680     out.close();
681     return true;
682 }
683 
CopyFileFast(const std::string & sourcePath,const std::string & destPath)684 bool BundleUtil::CopyFileFast(const std::string &sourcePath, const std::string &destPath)
685 {
686     APP_LOGI("sourcePath : %{public}s, destPath : %{public}s", sourcePath.c_str(), destPath.c_str());
687     if (sourcePath.empty() || destPath.empty()) {
688         APP_LOGE("invalid path");
689         return false;
690     }
691 
692     int32_t sourceFd = open(sourcePath.c_str(), O_RDONLY);
693     if (sourceFd == -1) {
694         APP_LOGE("sourcePath open failed, errno : %{public}d", errno);
695         return CopyFile(sourcePath, destPath);
696     }
697 
698     struct stat sourceStat;
699     if (fstat(sourceFd, &sourceStat) == -1) {
700         APP_LOGE("fstat failed, errno : %{public}d", errno);
701         close(sourceFd);
702         return CopyFile(sourcePath, destPath);
703     }
704     if (sourceStat.st_size < 0) {
705         APP_LOGE("invalid st_size");
706         close(sourceFd);
707         return CopyFile(sourcePath, destPath);
708     }
709 
710     int32_t destFd = open(
711         destPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
712     if (destFd == -1) {
713         APP_LOGE("destPath open failed, errno : %{public}d", errno);
714         close(sourceFd);
715         return CopyFile(sourcePath, destPath);
716     }
717 
718     size_t buffer = 524288; // 0.5M
719     size_t transferCount = 0;
720     ssize_t singleTransfer = 0;
721     while ((singleTransfer = sendfile(destFd, sourceFd, nullptr, buffer)) > 0) {
722         transferCount += static_cast<size_t>(singleTransfer);
723     }
724 
725     if (singleTransfer == -1 || transferCount != static_cast<size_t>(sourceStat.st_size)) {
726         APP_LOGE("sendfile failed, errno : %{public}d, send count : %{public}zu , file size : %{public}zu",
727             errno, transferCount, static_cast<size_t>(sourceStat.st_size));
728         close(sourceFd);
729         close(destFd);
730         return CopyFile(sourcePath, destPath);
731     }
732 
733     close(sourceFd);
734     close(destFd);
735     APP_LOGD("sendfile success");
736     return true;
737 }
738 
GetResource(const std::string & bundleName,const std::string & moduleName,uint32_t resId)739 Resource BundleUtil::GetResource(const std::string &bundleName, const std::string &moduleName, uint32_t resId)
740 {
741     Resource resource;
742     resource.bundleName = bundleName;
743     resource.moduleName = moduleName;
744     resource.id = resId;
745     return resource;
746 }
747 
CreateDir(const std::string & dir)748 bool BundleUtil::CreateDir(const std::string &dir)
749 {
750     if (dir.empty()) {
751         APP_LOGE("path is empty");
752         return false;
753     }
754 
755     if (IsExistFile(dir)) {
756         return true;
757     }
758 
759     if (!OHOS::ForceCreateDirectory(dir)) {
760         APP_LOGE("mkdir %{public}s failed", dir.c_str());
761         return false;
762     }
763 
764     if (chown(dir.c_str(), Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != 0) {
765         APP_LOGE("fail change %{public}s ownership, errno:%{public}d", dir.c_str(), errno);
766         return false;
767     }
768 
769     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
770     if (!OHOS::ChangeModeFile(dir, mode)) {
771         APP_LOGE("change mode failed, temp install dir : %{public}s", dir.c_str());
772         return false;
773     }
774     return true;
775 }
776 
RevertToRealPath(const std::string & sandBoxPath,const std::string & bundleName,std::string & realPath)777 bool BundleUtil::RevertToRealPath(const std::string &sandBoxPath, const std::string &bundleName, std::string &realPath)
778 {
779     if (sandBoxPath.empty() || bundleName.empty() ||
780         (sandBoxPath.find(ServiceConstants::SANDBOX_DATA_PATH) == std::string::npos &&
781         sandBoxPath.find(ServiceConstants::APP_INSTALL_SANDBOX_PATH) == std::string::npos)) {
782         APP_LOGE("input sandboxPath or bundleName invalid");
783         return false;
784     }
785 
786     realPath = sandBoxPath;
787     if (sandBoxPath.find(ServiceConstants::SANDBOX_DATA_PATH) == 0) {
788         std::string relaDataPath = std::string(ServiceConstants::REAL_DATA_PATH) + ServiceConstants::PATH_SEPARATOR
789             + std::to_string(BundleUtil::GetUserIdByCallingUid()) + ServiceConstants::BASE + bundleName;
790         realPath.replace(realPath.find(ServiceConstants::SANDBOX_DATA_PATH),
791             std::string(ServiceConstants::SANDBOX_DATA_PATH).size(), relaDataPath);
792     } else if (sandBoxPath.find(ServiceConstants::APP_INSTALL_SANDBOX_PATH) == 0) {
793         std::string relaDataPath = std::string(ServiceConstants::BUNDLE_MANAGER_SERVICE_PATH) +
794             ServiceConstants::GALLERY_DOWNLOAD_PATH + std::to_string(BundleUtil::GetUserIdByCallingUid());
795         realPath.replace(realPath.find(ServiceConstants::APP_INSTALL_SANDBOX_PATH),
796             std::string(ServiceConstants::APP_INSTALL_SANDBOX_PATH).size(), relaDataPath);
797     } else {
798         APP_LOGE("input sandboxPath invalid");
799         return false;
800     }
801     return true;
802 }
803 
StartWith(const std::string & source,const std::string & prefix)804 bool BundleUtil::StartWith(const std::string &source, const std::string &prefix)
805 {
806     if (source.empty() || prefix.empty()) {
807         return false;
808     }
809 
810     return source.find(prefix) == 0;
811 }
812 
EndWith(const std::string & source,const std::string & suffix)813 bool BundleUtil::EndWith(const std::string &source, const std::string &suffix)
814 {
815     if (source.empty() || suffix.empty()) {
816         return false;
817     }
818 
819     auto position = source.rfind(suffix);
820     if (position == std::string::npos) {
821         return false;
822     }
823 
824     std::string suffixStr = source.substr(position);
825     return suffixStr == suffix;
826 }
827 
GetFileSize(const std::string & filePath)828 int64_t BundleUtil::GetFileSize(const std::string &filePath)
829 {
830     struct stat fileInfo = { 0 };
831     if (stat(filePath.c_str(), &fileInfo) != 0) {
832         APP_LOGE("call stat error:%{public}d", errno);
833         return 0;
834     }
835     return fileInfo.st_size;
836 }
837 
CopyFileToSecurityDir(const std::string & filePath,const DirType & dirType,std::vector<std::string> & toDeletePaths,bool rename)838 std::string BundleUtil::CopyFileToSecurityDir(const std::string &filePath, const DirType &dirType,
839     std::vector<std::string> &toDeletePaths, bool rename)
840 {
841     APP_LOGD("the original dir is %{public}s", filePath.c_str());
842     std::string destination = "";
843     std::string subStr = "";
844     destination.append(ServiceConstants::HAP_COPY_PATH).append(ServiceConstants::PATH_SEPARATOR);
845     if (dirType == DirType::STREAM_INSTALL_DIR) {
846         subStr = ServiceConstants::STREAM_INSTALL_PATH;
847         destination.append(ServiceConstants::SECURITY_STREAM_INSTALL_PATH);
848         mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
849         if (InstalldClient::GetInstance()->Mkdir(
850             destination, mode, Constants::FOUNDATION_UID, ServiceConstants::BMS_GID) != ERR_OK) {
851             APP_LOGW("installd mkdir %{private}s failed", destination.c_str());
852         }
853     }
854     if (dirType == DirType::SIG_FILE_DIR) {
855         subStr = ServiceConstants::SIGNATURE_FILE_PATH;
856         destination.append(ServiceConstants::SECURITY_SIGNATURE_FILE_PATH);
857     }
858     destination.append(ServiceConstants::PATH_SEPARATOR).append(std::to_string(GetCurrentTimeNs()));
859     destination = CreateTempDir(destination);
860     auto pos = filePath.find(subStr);
861     if (pos == std::string::npos) { // this circumstance could not be considered laterly
862         auto lastPathSeperator = filePath.rfind(ServiceConstants::PATH_SEPARATOR);
863         if ((lastPathSeperator != std::string::npos) && (lastPathSeperator != filePath.length() - 1)) {
864             toDeletePaths.emplace_back(destination);
865             destination.append(filePath.substr(lastPathSeperator));
866         }
867     } else {
868         auto secondLastPathSep = filePath.find(ServiceConstants::PATH_SEPARATOR, pos);
869         if ((secondLastPathSep == std::string::npos) || (secondLastPathSep == filePath.length() - 1)) {
870             return "";
871         }
872         auto thirdLastPathSep =
873             filePath.find(ServiceConstants::PATH_SEPARATOR, secondLastPathSep + 1);
874         if ((thirdLastPathSep == std::string::npos) || (thirdLastPathSep == filePath.length() - 1)) {
875             return "";
876         }
877         toDeletePaths.emplace_back(destination);
878         std::string innerSubstr =
879             filePath.substr(secondLastPathSep, thirdLastPathSep - secondLastPathSep + 1);
880         destination = CreateTempDir(destination.append(innerSubstr));
881         destination.append(filePath.substr(thirdLastPathSep + 1));
882     }
883     APP_LOGD("the destination dir is %{public}s", destination.c_str());
884     if (destination.empty()) {
885         return "";
886     }
887     if (rename) {
888         APP_LOGD("rename file from %{public}s to %{public}s", filePath.c_str(), destination.c_str());
889         if (!RenameFile(filePath, destination)) {
890             APP_LOGE("rename file from %{public}s to %{public}s failed", filePath.c_str(), destination.c_str());
891             return "";
892         }
893     } else {
894         if (!CopyFileFast(filePath, destination)) {
895             APP_LOGE("copy file from %{public}s to %{public}s failed", filePath.c_str(), destination.c_str());
896             return "";
897         }
898     }
899     return destination;
900 }
901 
DeleteTempDirs(const std::vector<std::string> & tempDirs)902 void BundleUtil::DeleteTempDirs(const std::vector<std::string> &tempDirs)
903 {
904     for (const auto &tempDir : tempDirs) {
905         APP_LOGD("the temp hap dir %{public}s needs to be deleted", tempDir.c_str());
906         BundleUtil::DeleteDir(tempDir);
907     }
908 }
909 
GetHexHash(const std::string & s)910 std::string BundleUtil::GetHexHash(const std::string &s)
911 {
912     std::hash<std::string> hasher;
913     size_t hash = hasher(s);
914 
915     std::stringstream ss;
916     ss << std::hex << hash;
917 
918     std::string hash_str = ss.str();
919     return hash_str;
920 }
921 
RecursiveHash(std::string & s)922 void BundleUtil::RecursiveHash(std::string& s)
923 {
924     if (s.size() >= ORIGIN_STRING_LENGTH) {
925         s = s.substr(s.size() - ORIGIN_STRING_LENGTH);
926         return;
927     }
928     std::string hash = GetHexHash(s);
929     s += hash;
930     RecursiveHash(s);
931 }
932 
GenerateUuid()933 std::string BundleUtil::GenerateUuid()
934 {
935     std::lock_guard<std::mutex> lock(g_mutex);
936     auto currentTime = std::chrono::system_clock::now();
937     auto timestampNanoseconds =
938         std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime.time_since_epoch()).count();
939 
940     // convert nanosecond timestamps to string
941     std::string s = std::to_string(timestampNanoseconds);
942     std::string timeStr = GetHexHash(s);
943 
944     char deviceId[UUID_LENGTH_MAX] = { 0 };
945     auto ret = GetDevUdid(deviceId, UUID_LENGTH_MAX);
946     std::string deviceUdid;
947     std::string deviceStr;
948     if (ret != 0) {
949         APP_LOGW("GetDevUdid failed");
950     } else {
951         deviceUdid = std::string{ deviceId };
952         deviceStr = GetHexHash(deviceUdid);
953     }
954 
955     std::string uuid = timeStr + deviceStr;
956     RecursiveHash(uuid);
957 
958     for (int32_t index : SEPARATOR_POSITIONS) {
959         uuid.insert(index, 1, UUID_SEPARATOR);
960     }
961     return uuid;
962 }
963 
GenerateUuidByKey(const std::string & key)964 std::string BundleUtil::GenerateUuidByKey(const std::string &key)
965 {
966     std::string keyHash = GetHexHash(key);
967 
968     char deviceId[UUID_LENGTH_MAX] = { 0 };
969     auto ret = GetDevUdid(deviceId, UUID_LENGTH_MAX);
970     std::string deviceUdid;
971     std::string deviceStr;
972     if (ret != 0) {
973         APP_LOGW("GetDevUdid failed");
974     } else {
975         deviceUdid = std::string{ deviceId };
976         deviceStr = GetHexHash(deviceUdid);
977     }
978 
979     std::string uuid = keyHash + deviceStr;
980     RecursiveHash(uuid);
981 
982     for (int32_t index : SEPARATOR_POSITIONS) {
983         uuid.insert(index, 1, UUID_SEPARATOR);
984     }
985     return uuid;
986 }
987 
ExtractGroupIdByDevelopId(const std::string & developerId)988 std::string BundleUtil::ExtractGroupIdByDevelopId(const std::string &developerId)
989 {
990     std::string::size_type dot_position = developerId.find('.');
991     if (dot_position == std::string::npos) {
992         // If cannot find '.' , the input string is developerId, return developerId
993         return developerId;
994     }
995     if (dot_position == 0) {
996         // if'.' In the first place, then groupId is empty, return developerId
997         return developerId.substr(1);
998     }
999     // If '.' If it is not the first place, there is a groupId, and the groupId is returned
1000     return developerId.substr(0, dot_position);
1001 }
1002 
ToString(const std::vector<std::string> & vector)1003 std::string BundleUtil::ToString(const std::vector<std::string> &vector)
1004 {
1005     std::string ret;
1006     for (const std::string &item : vector) {
1007         ret.append(item).append(",");
1008     }
1009     return ret;
1010 }
1011 
GetNoDisablingConfigPath()1012 std::string BundleUtil::GetNoDisablingConfigPath()
1013 {
1014 #ifdef CONFIG_POLOCY_ENABLE
1015     char buf[MAX_PATH_LEN] = { 0 };
1016     char *configPath = GetOneCfgFile(NO_DISABLING_CONFIG_PATH, buf, MAX_PATH_LEN);
1017     if (configPath == nullptr || configPath[0] == '\0') {
1018         APP_LOGE("BundleUtil GetOneCfgFile failed");
1019         return NO_DISABLING_CONFIG_PATH_DEFAULT;
1020     }
1021     if (strlen(configPath) > MAX_PATH_LEN) {
1022         APP_LOGE("length exceeds");
1023         return NO_DISABLING_CONFIG_PATH_DEFAULT;
1024     }
1025     return configPath;
1026 #else
1027     return NO_DISABLING_CONFIG_PATH_DEFAULT;
1028 #endif
1029 }
1030 }  // namespace AppExecFwk
1031 }  // namespace OHOS
1032