• 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 "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