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 "bundle_util.h"
17
18 #include <algorithm>
19 #include <chrono>
20 #include <cinttypes>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <fstream>
24 #include <set>
25 #include <sys/sendfile.h>
26 #include <sys/stat.h>
27 #include <sys/statfs.h>
28 #include <thread>
29 #include <unistd.h>
30
31 #include "app_log_wrapper.h"
32 #include "bundle_constants.h"
33 #include "directory_ex.h"
34 #include "hitrace_meter.h"
35 #include "installd_client.h"
36 #include "ipc_skeleton.h"
37 #include "string_ex.h"
38
39 namespace OHOS {
40 namespace AppExecFwk {
41 namespace {
42 const std::string::size_type EXPECT_SPLIT_SIZE = 2;
43 const char START_CHAR = 'a';
44 const size_t ZERO = 0;
45 const size_t ORIGIN_STRING_LENGTH = 32;
46 const std::string DATA_GROUP_DIR_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 double SAVE_SPACE_PERCENT = 0.05;
50 static std::string g_deviceUdid;
51 static std::mutex g_mutex;
52 // hmdfs and sharefs config
53 constexpr const char* BUNDLE_ID_FILE = "appid";
54 }
55
CheckFilePath(const std::string & bundlePath,std::string & realPath)56 ErrCode BundleUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
57 {
58 if (!CheckFileName(bundlePath)) {
59 APP_LOGE("bundle file path invalid");
60 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
61 }
62 if (!CheckFileType(bundlePath, Constants::INSTALL_FILE_SUFFIX) &&
63 !CheckFileType(bundlePath, Constants::HSP_FILE_SUFFIX) &&
64 !CheckFileType(bundlePath, Constants::QUICK_FIX_FILE_SUFFIX) &&
65 !CheckFileType(bundlePath, Constants::CODE_SIGNATURE_FILE_SUFFIX)) {
66 APP_LOGE("file is not hap, hsp, hqf or sig");
67 return ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME;
68 }
69 if (!PathToRealPath(bundlePath, realPath)) {
70 APP_LOGE("file is not real path");
71 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
72 }
73 if (access(realPath.c_str(), F_OK) != 0) {
74 APP_LOGE("can not access the bundle file path: %{public}s", realPath.c_str());
75 return ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE;
76 }
77 if (!CheckFileSize(realPath, Constants::MAX_HAP_SIZE)) {
78 APP_LOGE("file size is larger than max hap size Max size is: %{public}" PRId64, Constants::MAX_HAP_SIZE);
79 return ERR_APPEXECFWK_INSTALL_INVALID_HAP_SIZE;
80 }
81 return ERR_OK;
82 }
83
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)84 ErrCode BundleUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
85 {
86 HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
87 // there are three cases for bundlePaths:
88 // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
89 // 2. one hap direction in the bundlePaths.
90 // 3. some hap file directions in the bundlePaths.
91 APP_LOGD("check file path");
92 if (bundlePaths.empty()) {
93 APP_LOGE("bundle file paths invalid");
94 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
95 }
96 ErrCode ret = ERR_OK;
97
98 if (bundlePaths.size() == 1) {
99 struct stat s;
100 std::string bundlePath = bundlePaths.front();
101 if (stat(bundlePath.c_str(), &s) == 0) {
102 std::string realPath = "";
103 // it is a direction
104 if ((s.st_mode & S_IFDIR) && !GetHapFilesFromBundlePath(bundlePath, realPaths)) {
105 APP_LOGE("GetHapFilesFromBundlePath failed with bundlePath:%{public}s", bundlePaths.front().c_str());
106 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
107 }
108 // it is a file
109 if ((s.st_mode & S_IFREG) && (ret = CheckFilePath(bundlePaths.front(), realPath)) == ERR_OK) {
110 realPaths.emplace_back(realPath);
111 }
112 return ret;
113 } else {
114 APP_LOGE("bundlePath is not existed with :%{public}s", bundlePaths.front().c_str());
115 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
116 }
117 } else {
118 for (const std::string& bundlePath : bundlePaths) {
119 std::string realPath = "";
120 ret = CheckFilePath(bundlePath, realPath);
121 if (ret != ERR_OK) {
122 return ret;
123 }
124 realPaths.emplace_back(realPath);
125 }
126 }
127 APP_LOGD("finish check file path");
128 return ret;
129 }
130
CheckFileType(const std::string & fileName,const std::string & extensionName)131 bool BundleUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
132 {
133 APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
134 if (!CheckFileName(fileName)) {
135 return false;
136 }
137
138 auto position = fileName.rfind('.');
139 if (position == std::string::npos) {
140 APP_LOGE("filename no extension name");
141 return false;
142 }
143
144 std::string suffixStr = fileName.substr(position);
145 return LowerStr(suffixStr) == extensionName;
146 }
147
CheckFileName(const std::string & fileName)148 bool BundleUtil::CheckFileName(const std::string &fileName)
149 {
150 if (fileName.empty()) {
151 APP_LOGE("the file name is empty");
152 return false;
153 }
154 if (fileName.size() > Constants::PATH_MAX_SIZE) {
155 APP_LOGE("bundle file path length %{public}zu too long", fileName.size());
156 return false;
157 }
158 return true;
159 }
160
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)161 bool BundleUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
162 {
163 APP_LOGD("fileSize is %{public}" PRId64, fileSize / Constants::ONE_GB);
164 struct stat fileInfo = { 0 };
165 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
166 APP_LOGE("call stat error");
167 return false;
168 }
169 if (fileInfo.st_size > fileSize) {
170 return false;
171 }
172 return true;
173 }
174
CheckSystemSize(const std::string & bundlePath,const std::string & diskPath)175 bool BundleUtil::CheckSystemSize(const std::string &bundlePath, const std::string &diskPath)
176 {
177 struct statfs diskInfo = { 0 };
178 if (statfs(diskPath.c_str(), &diskInfo) != 0) {
179 APP_LOGE("call statfs error");
180 return false;
181 }
182 int64_t freeSize = diskInfo.f_bfree * diskInfo.f_bsize;
183 APP_LOGD("left free size in the disk path is %{public}" PRId64, freeSize / Constants::ONE_GB);
184
185 // bundleSize + keepSize <= system-freeSize needs to be satisfied
186 return CheckFileSize(bundlePath, freeSize - std::min(freeSize * SAVE_SPACE_PERCENT, static_cast<double>(HALF_GB)));
187 }
188
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)189 bool BundleUtil::GetHapFilesFromBundlePath(const std::string& currentBundlePath, std::vector<std::string>& hapFileList)
190 {
191 APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
192 if (currentBundlePath.empty()) {
193 return false;
194 }
195 DIR* dir = opendir(currentBundlePath.c_str());
196 if (dir == nullptr) {
197 char errMsg[256] = {0};
198 strerror_r(errno, errMsg, sizeof(errMsg));
199 APP_LOGE("GetHapFilesFromBundlePath open bundle dir:%{public}s is failure due to %{public}s",
200 currentBundlePath.c_str(), errMsg);
201 return false;
202 }
203 std::string bundlePath = currentBundlePath;
204 if (bundlePath.back() != Constants::FILE_SEPARATOR_CHAR) {
205 bundlePath.append(Constants::PATH_SEPARATOR);
206 }
207 struct dirent *entry = nullptr;
208 while ((entry = readdir(dir)) != nullptr) {
209 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
210 continue;
211 }
212 const std::string hapFilePath = bundlePath + entry->d_name;
213 std::string realPath = "";
214 if (CheckFilePath(hapFilePath, realPath) != ERR_OK) {
215 APP_LOGE("find invalid hap path %{public}s", hapFilePath.c_str());
216 closedir(dir);
217 return false;
218 }
219 hapFileList.emplace_back(realPath);
220 APP_LOGD("find hap path %{public}s", realPath.c_str());
221
222 if (!hapFileList.empty() && (hapFileList.size() > Constants::MAX_HAP_NUMBER)) {
223 APP_LOGE("reach the max hap number 128, stop to add more.");
224 closedir(dir);
225 return false;
226 }
227 }
228 closedir(dir);
229 return true;
230 }
231
GetCurrentTime()232 int64_t BundleUtil::GetCurrentTime()
233 {
234 int64_t time =
235 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
236 .count();
237 APP_LOGD("the current time in seconds is %{public}" PRId64, time);
238 return time;
239 }
240
GetCurrentTimeMs()241 int64_t BundleUtil::GetCurrentTimeMs()
242 {
243 int64_t time =
244 std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
245 .count();
246 APP_LOGD("the current time in milliseconds is %{public}" PRId64, time);
247 return time;
248 }
249
DeviceAndNameToKey(const std::string & deviceId,const std::string & bundleName,std::string & key)250 void BundleUtil::DeviceAndNameToKey(
251 const std::string &deviceId, const std::string &bundleName, std::string &key)
252 {
253 key.append(deviceId);
254 key.append(Constants::FILE_UNDERLINE);
255 key.append(bundleName);
256 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
257 }
258
KeyToDeviceAndName(const std::string & key,std::string & deviceId,std::string & bundleName)259 bool BundleUtil::KeyToDeviceAndName(
260 const std::string &key, std::string &deviceId, std::string &bundleName)
261 {
262 bool ret = false;
263 std::vector<std::string> splitStrs;
264 OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs);
265 // the expect split size should be 2.
266 // key rule is <deviceId>_<bundleName>
267 if (splitStrs.size() == EXPECT_SPLIT_SIZE) {
268 deviceId = splitStrs[0];
269 bundleName = splitStrs[1];
270 ret = true;
271 }
272 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
273 return ret;
274 }
275
GetUserIdByCallingUid()276 int32_t BundleUtil::GetUserIdByCallingUid()
277 {
278 int32_t uid = IPCSkeleton::GetCallingUid();
279 APP_LOGD("get calling uid(%{public}d)", uid);
280 return GetUserIdByUid(uid);
281 }
282
GetUserIdByUid(int32_t uid)283 int32_t BundleUtil::GetUserIdByUid(int32_t uid)
284 {
285 if (uid <= Constants::INVALID_UID) {
286 APP_LOGE("uid is illegal: %{public}d", uid);
287 return Constants::INVALID_USERID;
288 }
289
290 return uid / Constants::BASE_USER_RANGE;
291 }
292
MakeFsConfig(const std::string & bundleName,int32_t bundleId,const std::string & configPath)293 void BundleUtil::MakeFsConfig(const std::string &bundleName, int32_t bundleId, const std::string &configPath)
294 {
295 std::string bundleDir = configPath + Constants::PATH_SEPARATOR + bundleName;
296 if (access(bundleDir.c_str(), F_OK) != 0) {
297 if (mkdir(bundleDir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
298 APP_LOGE("make bundle dir error");
299 return;
300 }
301 }
302
303 std::string realBundleDir;
304 if (!PathToRealPath(bundleDir, realBundleDir)) {
305 APP_LOGE("bundleIdFile is not real path");
306 return;
307 }
308
309 realBundleDir += (Constants::PATH_SEPARATOR + BUNDLE_ID_FILE);
310
311 int32_t bundleIdFd = open(realBundleDir.c_str(), O_WRONLY | O_TRUNC);
312 if (bundleIdFd > 0) {
313 std::string bundleIdStr = std::to_string(bundleId);
314 if (write(bundleIdFd, bundleIdStr.c_str(), bundleIdStr.size()) < 0) {
315 APP_LOGE("write bundleId error");
316 }
317 }
318 close(bundleIdFd);
319 }
320
RemoveFsConfig(const std::string & bundleName,const std::string & configPath)321 void BundleUtil::RemoveFsConfig(const std::string &bundleName, const std::string &configPath)
322 {
323 std::string bundleDir = configPath + Constants::PATH_SEPARATOR + bundleName;
324 std::string realBundleDir;
325 if (!PathToRealPath(bundleDir, realBundleDir)) {
326 APP_LOGE("bundleDir is not real path");
327 return;
328 }
329 if (rmdir(realBundleDir.c_str()) != 0) {
330 APP_LOGE("remove hmdfs bundle dir error");
331 }
332 }
333
CreateTempDir(const std::string & tempDir)334 std::string BundleUtil::CreateTempDir(const std::string &tempDir)
335 {
336 if (!OHOS::ForceCreateDirectory(tempDir)) {
337 APP_LOGE("mkdir %{public}s failed", tempDir.c_str());
338 return "";
339 }
340 if (chown(tempDir.c_str(), Constants::FOUNDATION_UID, Constants::BMS_GID) != 0) {
341 APP_LOGE("fail to change %{public}s ownership", tempDir.c_str());
342 return "";
343 }
344 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
345 if (!OHOS::ChangeModeFile(tempDir, mode)) {
346 APP_LOGE("change mode failed, temp install dir : %{public}s", tempDir.c_str());
347 return "";
348 }
349 return tempDir;
350 }
351
CreateInstallTempDir(uint32_t installerId,const DirType & type)352 std::string BundleUtil::CreateInstallTempDir(uint32_t installerId, const DirType &type)
353 {
354 std::time_t curTime = std::time(0);
355 std::string tempDir = Constants::HAP_COPY_PATH;
356 if (type == DirType::STREAM_INSTALL_DIR) {
357 tempDir += Constants::PATH_SEPARATOR + Constants::STREAM_INSTALL_PATH;
358 } else if (type == DirType::QUICK_FIX_DIR) {
359 tempDir += Constants::PATH_SEPARATOR + Constants::QUICK_FIX_PATH;
360 } else if (type == DirType::SIG_FILE_DIR) {
361 tempDir += Constants::PATH_SEPARATOR + Constants::SIGNATURE_FILE_PATH;
362 } else if (type == DirType::PGO_FILE_DIR) {
363 tempDir += Constants::PATH_SEPARATOR + Constants::PGO_FILE_PATH;
364 } else if (type == DirType::ABC_FILE_DIR) {
365 tempDir += Constants::PATH_SEPARATOR + Constants::ABC_FILE_PATH;
366 } else {
367 return "";
368 }
369
370 if (CreateTempDir(tempDir).empty()) {
371 APP_LOGE("create tempDir failed");
372 return "";
373 }
374
375 tempDir += Constants::PATH_SEPARATOR + std::to_string(curTime) +
376 std::to_string(installerId) + Constants::PATH_SEPARATOR;
377 return CreateTempDir(tempDir);
378 }
379
CreateSharedBundleTempDir(uint32_t installerId,uint32_t index)380 std::string BundleUtil::CreateSharedBundleTempDir(uint32_t installerId, uint32_t index)
381 {
382 std::time_t curTime = std::time(0);
383 std::string tempDir = Constants::HAP_COPY_PATH;
384 tempDir += Constants::PATH_SEPARATOR + Constants::STREAM_INSTALL_PATH;
385 tempDir += Constants::PATH_SEPARATOR + std::to_string(curTime) +
386 std::to_string(installerId) + Constants::FILE_UNDERLINE + std::to_string(index) + Constants::PATH_SEPARATOR;
387 return CreateTempDir(tempDir);
388 }
389
CreateFileDescriptor(const std::string & bundlePath,long long offset)390 int32_t BundleUtil::CreateFileDescriptor(const std::string &bundlePath, long long offset)
391 {
392 int fd = -1;
393 if (bundlePath.length() > Constants::PATH_MAX_SIZE) {
394 APP_LOGE("the length of the bundlePath exceeds maximum limitation");
395 return fd;
396 }
397 if ((fd = open(bundlePath.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
398 APP_LOGE("open bundlePath %{public}s failed", bundlePath.c_str());
399 return fd;
400 }
401 if (offset > 0) {
402 lseek(fd, offset, SEEK_SET);
403 }
404 return fd;
405 }
406
CreateFileDescriptorForReadOnly(const std::string & bundlePath,long long offset)407 int32_t BundleUtil::CreateFileDescriptorForReadOnly(const std::string &bundlePath, long long offset)
408 {
409 int fd = -1;
410 if (bundlePath.length() > Constants::PATH_MAX_SIZE) {
411 APP_LOGE("the length of the bundlePath exceeds maximum limitation");
412 return fd;
413 }
414 std::string realPath;
415 if (!PathToRealPath(bundlePath, realPath)) {
416 APP_LOGE("file is not real path");
417 return fd;
418 }
419
420 if ((fd = open(realPath.c_str(), O_RDONLY)) < 0) {
421 APP_LOGE("open bundlePath %{public}s failed", realPath.c_str());
422 return fd;
423 }
424 if (offset > 0) {
425 lseek(fd, offset, SEEK_SET);
426 }
427 return fd;
428 }
429
CloseFileDescriptor(std::vector<int32_t> & fdVec)430 void BundleUtil::CloseFileDescriptor(std::vector<int32_t> &fdVec)
431 {
432 for_each(fdVec.begin(), fdVec.end(), [](const auto &fd) {
433 if (fd > 0) {
434 close(fd);
435 }
436 });
437 fdVec.clear();
438 }
439
IsExistFile(const std::string & path)440 bool BundleUtil::IsExistFile(const std::string &path)
441 {
442 if (path.empty()) {
443 return false;
444 }
445
446 struct stat buf = {};
447 if (stat(path.c_str(), &buf) != 0) {
448 return false;
449 }
450
451 return S_ISREG(buf.st_mode);
452 }
453
IsExistDir(const std::string & path)454 bool BundleUtil::IsExistDir(const std::string &path)
455 {
456 if (path.empty()) {
457 return false;
458 }
459
460 struct stat buf = {};
461 if (stat(path.c_str(), &buf) != 0) {
462 return false;
463 }
464
465 return S_ISDIR(buf.st_mode);
466 }
467
CalculateFileSize(const std::string & bundlePath)468 int64_t BundleUtil::CalculateFileSize(const std::string &bundlePath)
469 {
470 struct stat fileInfo = { 0 };
471 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
472 APP_LOGE("call stat error");
473 return 0;
474 }
475
476 return static_cast<int64_t>(fileInfo.st_size);
477 }
478
RenameFile(const std::string & oldPath,const std::string & newPath)479 bool BundleUtil::RenameFile(const std::string &oldPath, const std::string &newPath)
480 {
481 if (oldPath.empty() || newPath.empty()) {
482 APP_LOGE("oldPath or newPath is empty");
483 return false;
484 }
485
486 if (!DeleteDir(newPath)) {
487 APP_LOGE("delete newPath failed");
488 return false;
489 }
490
491 return rename(oldPath.c_str(), newPath.c_str()) == 0;
492 }
493
DeleteDir(const std::string & path)494 bool BundleUtil::DeleteDir(const std::string &path)
495 {
496 if (IsExistFile(path)) {
497 return OHOS::RemoveFile(path);
498 }
499
500 if (IsExistDir(path)) {
501 return OHOS::ForceRemoveDirectory(path);
502 }
503
504 return true;
505 }
506
GetBoolStrVal(bool val)507 std::string BundleUtil::GetBoolStrVal(bool val)
508 {
509 return val ? "true" : "false";
510 }
511
CopyFile(const std::string & sourceFile,const std::string & destinationFile)512 bool BundleUtil::CopyFile(
513 const std::string &sourceFile, const std::string &destinationFile)
514 {
515 if (sourceFile.empty() || destinationFile.empty()) {
516 APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
517 return false;
518 }
519
520 std::ifstream in(sourceFile);
521 if (!in.is_open()) {
522 APP_LOGE("Copy file failed due to open sourceFile failed");
523 return false;
524 }
525
526 std::ofstream out(destinationFile);
527 if (!out.is_open()) {
528 APP_LOGE("Copy file failed due to open destinationFile failed");
529 in.close();
530 return false;
531 }
532
533 out << in.rdbuf();
534 in.close();
535 out.close();
536 return true;
537 }
538
CopyFileFast(const std::string & sourcePath,const std::string & destPath)539 bool BundleUtil::CopyFileFast(const std::string &sourcePath, const std::string &destPath)
540 {
541 APP_LOGI("sourcePath : %{public}s, destPath : %{public}s", sourcePath.c_str(), destPath.c_str());
542 if (sourcePath.empty() || destPath.empty()) {
543 APP_LOGE("invalid path");
544 return false;
545 }
546
547 int32_t sourceFd = open(sourcePath.c_str(), O_RDONLY);
548 if (sourceFd == -1) {
549 APP_LOGE("sourcePath open failed, errno : %{public}d", errno);
550 return CopyFile(sourcePath, destPath);
551 }
552
553 struct stat sourceStat;
554 if (fstat(sourceFd, &sourceStat) == -1) {
555 APP_LOGE("fstat failed, errno : %{public}d", errno);
556 close(sourceFd);
557 return CopyFile(sourcePath, destPath);
558 }
559 if (sourceStat.st_size < 0) {
560 APP_LOGE("invalid st_size");
561 close(sourceFd);
562 return CopyFile(sourcePath, destPath);
563 }
564
565 int32_t destFd = open(
566 destPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
567 if (destFd == -1) {
568 APP_LOGE("destPath open failed, errno : %{public}d", errno);
569 close(sourceFd);
570 return CopyFile(sourcePath, destPath);
571 }
572
573 size_t buffer = 524288; // 0.5M
574 size_t transferCount = 0;
575 ssize_t singleTransfer = 0;
576 while ((singleTransfer = sendfile(destFd, sourceFd, nullptr, buffer)) > 0) {
577 transferCount += static_cast<size_t>(singleTransfer);
578 }
579
580 if (singleTransfer == -1 || transferCount != static_cast<size_t>(sourceStat.st_size)) {
581 APP_LOGE("sendfile failed, errno : %{public}d, send count : %{public}zu , file size : %{public}zu",
582 errno, transferCount, static_cast<size_t>(sourceStat.st_size));
583 close(sourceFd);
584 close(destFd);
585 return CopyFile(sourcePath, destPath);
586 }
587
588 close(sourceFd);
589 close(destFd);
590 APP_LOGI("sendfile success");
591 return true;
592 }
593
GetResource(const std::string & bundleName,const std::string & moduleName,int32_t resId)594 Resource BundleUtil::GetResource(const std::string &bundleName, const std::string &moduleName, int32_t resId)
595 {
596 Resource resource;
597 resource.bundleName = bundleName;
598 resource.moduleName = moduleName;
599 resource.id = resId;
600 return resource;
601 }
602
CreateDir(const std::string & dir)603 bool BundleUtil::CreateDir(const std::string &dir)
604 {
605 if (dir.empty()) {
606 APP_LOGE("path is empty");
607 return false;
608 }
609
610 if (IsExistFile(dir)) {
611 return true;
612 }
613
614 if (!OHOS::ForceCreateDirectory(dir)) {
615 APP_LOGE("mkdir %{public}s failed", dir.c_str());
616 return false;
617 }
618
619 if (chown(dir.c_str(), Constants::FOUNDATION_UID, Constants::BMS_GID) != 0) {
620 APP_LOGE("fail to change %{public}s ownership", dir.c_str());
621 return false;
622 }
623
624 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
625 if (!OHOS::ChangeModeFile(dir, mode)) {
626 APP_LOGE("change mode failed, temp install dir : %{public}s", dir.c_str());
627 return false;
628 }
629 return true;
630 }
631
RevertToRealPath(const std::string & sandBoxPath,const std::string & bundleName,std::string & realPath)632 bool BundleUtil::RevertToRealPath(const std::string &sandBoxPath, const std::string &bundleName, std::string &realPath)
633 {
634 if (sandBoxPath.empty() || bundleName.empty() ||
635 sandBoxPath.find(Constants::SANDBOX_DATA_PATH) == std::string::npos) {
636 APP_LOGE("input sandboxPath or bundleName invalid");
637 return false;
638 }
639
640 realPath = sandBoxPath;
641 std::string relaDataPath = Constants::REAL_DATA_PATH + Constants::PATH_SEPARATOR
642 + std::to_string(BundleUtil::GetUserIdByCallingUid()) + Constants::BASE + bundleName;
643 realPath.replace(realPath.find(Constants::SANDBOX_DATA_PATH),
644 std::string(Constants::SANDBOX_DATA_PATH).size(), relaDataPath);
645 return true;
646 }
647
StartWith(const std::string & source,const std::string & prefix)648 bool BundleUtil::StartWith(const std::string &source, const std::string &prefix)
649 {
650 if (source.empty() || prefix.empty()) {
651 return false;
652 }
653
654 return source.find(prefix) == 0;
655 }
656
EndWith(const std::string & source,const std::string & suffix)657 bool BundleUtil::EndWith(const std::string &source, const std::string &suffix)
658 {
659 if (source.empty() || suffix.empty()) {
660 return false;
661 }
662
663 auto position = source.rfind(suffix);
664 if (position == std::string::npos) {
665 return false;
666 }
667
668 std::string suffixStr = source.substr(position);
669 return suffixStr == suffix;
670 }
671
GetFileSize(const std::string & filePath)672 int64_t BundleUtil::GetFileSize(const std::string &filePath)
673 {
674 struct stat fileInfo = { 0 };
675 if (stat(filePath.c_str(), &fileInfo) != 0) {
676 APP_LOGE("call stat error");
677 return 0;
678 }
679 return fileInfo.st_size;
680 }
681
CopyFileToSecurityDir(const std::string & filePath,const DirType & dirType,std::vector<std::string> & toDeletePaths)682 std::string BundleUtil::CopyFileToSecurityDir(const std::string &filePath, const DirType &dirType,
683 std::vector<std::string> &toDeletePaths)
684 {
685 APP_LOGD("the original dir is %{public}s", filePath.c_str());
686 std::string destination = "";
687 std::string subStr = "";
688 destination.append(Constants::HAP_COPY_PATH).append(Constants::PATH_SEPARATOR);
689 if (dirType == DirType::STREAM_INSTALL_DIR) {
690 subStr = Constants::STREAM_INSTALL_PATH;
691 destination.append(Constants::SECURITY_STREAM_INSTALL_PATH);
692 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
693 if (InstalldClient::GetInstance()->Mkdir(
694 destination, mode, Constants::FOUNDATION_UID, Constants::BMS_GID) != ERR_OK) {
695 APP_LOGW("installd mkdir %{private}s failed", destination.c_str());
696 }
697 }
698 if (dirType == DirType::SIG_FILE_DIR) {
699 subStr = Constants::SIGNATURE_FILE_PATH;
700 destination.append(Constants::SECURITY_SIGNATURE_FILE_PATH);
701 }
702 destination.append(Constants::PATH_SEPARATOR).append(std::to_string(GetCurrentTimeMs()));
703 destination = CreateTempDir(destination);
704 auto pos = filePath.find(subStr);
705 if (pos == std::string::npos) { // this circumstance could not be considered laterly
706 auto lastPathSeperator = filePath.rfind(Constants::PATH_SEPARATOR);
707 if ((lastPathSeperator != std::string::npos) && (lastPathSeperator != filePath.length() - 1)) {
708 toDeletePaths.emplace_back(destination);
709 destination.append(filePath.substr(lastPathSeperator));
710 }
711 } else {
712 auto secondLastPathSep = filePath.find(Constants::PATH_SEPARATOR, pos);
713 if ((secondLastPathSep == std::string::npos) || (secondLastPathSep == filePath.length() - 1)) {
714 return "";
715 }
716 auto thirdLastPathSep =
717 filePath.find(Constants::PATH_SEPARATOR, secondLastPathSep + 1);
718 if ((thirdLastPathSep == std::string::npos) || (thirdLastPathSep == filePath.length() - 1)) {
719 return "";
720 }
721 toDeletePaths.emplace_back(destination);
722 std::string innerSubstr =
723 filePath.substr(secondLastPathSep, thirdLastPathSep - secondLastPathSep + 1);
724 destination = CreateTempDir(destination.append(innerSubstr));
725 destination.append(filePath.substr(thirdLastPathSep + 1));
726 }
727 APP_LOGD("the destination dir is %{public}s", destination.c_str());
728 if (destination.empty()) {
729 return "";
730 }
731 if (!CopyFileFast(filePath, destination)) {
732 APP_LOGE("copy file from %{public}s to %{public}s failed", filePath.c_str(), destination.c_str());
733 return "";
734 }
735 return destination;
736 }
737
DeleteTempDirs(const std::vector<std::string> & tempDirs)738 void BundleUtil::DeleteTempDirs(const std::vector<std::string> &tempDirs)
739 {
740 for (const auto &tempDir : tempDirs) {
741 APP_LOGD("the temp hap dir %{public}s needs to be deleted", tempDir.c_str());
742 BundleUtil::DeleteDir(tempDir);
743 }
744 }
745
GenerateDataGroupDirName()746 std::string BundleUtil::GenerateDataGroupDirName()
747 {
748 auto currentTime = std::chrono::system_clock::now();
749 auto timestampNanoseconds =
750 std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime.time_since_epoch()).count();
751
752 // convert nanosecond timestamps to string
753 std::string timestampString = std::to_string(timestampNanoseconds);
754 if (timestampString.size() < ORIGIN_STRING_LENGTH) {
755 for (size_t i = ZERO; i < ORIGIN_STRING_LENGTH - timestampString.size(); i++) {
756 timestampString += static_cast<char>(START_CHAR + i);
757 }
758 } else {
759 timestampString = timestampString.substr(ZERO, ORIGIN_STRING_LENGTH);
760 }
761
762 for (int32_t index : SEPARATOR_POSITIONS) {
763 timestampString.insert(index, DATA_GROUP_DIR_SEPARATOR);
764 }
765 return timestampString;
766 }
767 } // namespace AppExecFwk
768 } // namespace OHOS
769