• 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 <chrono>
19 #include <cinttypes>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <sys/stat.h>
24 #include <sys/statfs.h>
25 #include <thread>
26 #include <unistd.h>
27 
28 #include "app_log_wrapper.h"
29 #include "bundle_constants.h"
30 #include "hitrace_meter.h"
31 #include "directory_ex.h"
32 #include "ipc_skeleton.h"
33 #include "string_ex.h"
34 
35 namespace OHOS {
36 namespace AppExecFwk {
37 namespace {
38 const std::string::size_type EXPECT_SPLIT_SIZE = 2;
39 static std::string g_deviceUdid;
40 static std::mutex g_mutex;
41 }
42 
CheckFilePath(const std::string & bundlePath,std::string & realPath)43 ErrCode BundleUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
44 {
45     if (!CheckFileName(bundlePath)) {
46         APP_LOGE("bundle file path invalid");
47         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
48     }
49     if (!CheckFileType(bundlePath, Constants::INSTALL_FILE_SUFFIX) &&
50         !CheckFileType(bundlePath, Constants::INSTALL_SHARED_FILE_SUFFIX) &&
51         !CheckFileType(bundlePath, Constants::QUICK_FIX_FILE_SUFFIX)) {
52         APP_LOGE("file is not hap, hsp or hqf");
53         return ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME;
54     }
55     if (!PathToRealPath(bundlePath, realPath)) {
56         APP_LOGE("file is not real path");
57         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
58     }
59     if (access(realPath.c_str(), F_OK) != 0) {
60         APP_LOGE("can not access the bundle file path: %{private}s", realPath.c_str());
61         return ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE;
62     }
63     if (!CheckFileSize(realPath, Constants::MAX_HAP_SIZE)) {
64         APP_LOGE("file size is larger than max hap size Max size is: %{public}" PRId64, Constants::MAX_HAP_SIZE);
65         return ERR_APPEXECFWK_INSTALL_INVALID_HAP_SIZE;
66     }
67     return ERR_OK;
68 }
69 
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)70 ErrCode BundleUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
71 {
72     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
73     // there are three cases for bundlePaths:
74     // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
75     // 2. one hap direction in the bundlePaths.
76     // 3. some hap file directions in the bundlePaths.
77     APP_LOGD("check file path");
78     if (bundlePaths.empty()) {
79         APP_LOGE("bundle file paths invalid");
80         return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
81     }
82     ErrCode ret = ERR_OK;
83 
84     if (bundlePaths.size() == 1) {
85         struct stat s;
86         std::string bundlePath = bundlePaths.front();
87         if (stat(bundlePath.c_str(), &s) == 0) {
88             std::string realPath = "";
89             // it is a direction
90             if ((s.st_mode & S_IFDIR) && !GetHapFilesFromBundlePath(bundlePath, realPaths)) {
91                 APP_LOGE("GetHapFilesFromBundlePath failed with bundlePath:%{private}s", bundlePaths.front().c_str());
92                 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
93             }
94             // it is a file
95             if ((s.st_mode & S_IFREG) && (ret = CheckFilePath(bundlePaths.front(), realPath)) == ERR_OK) {
96                 realPaths.emplace_back(realPath);
97             }
98             return ret;
99         } else {
100             APP_LOGE("bundlePath is not existed with :%{private}s", bundlePaths.front().c_str());
101             return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
102         }
103     } else {
104         for (const std::string& bundlePath : bundlePaths) {
105             std::string realPath = "";
106             ret = CheckFilePath(bundlePath, realPath);
107             if (ret != ERR_OK) {
108                 return ret;
109             }
110             realPaths.emplace_back(realPath);
111         }
112     }
113     APP_LOGD("finish check file path");
114     return ret;
115 }
116 
CheckFileType(const std::string & fileName,const std::string & extensionName)117 bool BundleUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
118 {
119     APP_LOGD("path is %{private}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
120     if (!CheckFileName(fileName)) {
121         return false;
122     }
123 
124     auto position = fileName.rfind('.');
125     if (position == std::string::npos) {
126         APP_LOGE("filename no extension name");
127         return false;
128     }
129 
130     std::string suffixStr = fileName.substr(position);
131     return LowerStr(suffixStr) == extensionName;
132 }
133 
CheckFileName(const std::string & fileName)134 bool BundleUtil::CheckFileName(const std::string &fileName)
135 {
136     if (fileName.empty()) {
137         APP_LOGE("the file name is empty");
138         return false;
139     }
140     if (fileName.size() > Constants::PATH_MAX_SIZE) {
141         APP_LOGE("bundle file path length %{public}zu too long", fileName.size());
142         return false;
143     }
144     return true;
145 }
146 
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)147 bool BundleUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
148 {
149     struct stat fileInfo = { 0 };
150     if (stat(bundlePath.c_str(), &fileInfo) != 0) {
151         APP_LOGE("call stat error");
152         return false;
153     }
154     if (fileInfo.st_size > fileSize) {
155         return false;
156     }
157     return true;
158 }
159 
CheckSystemSize(const std::string & bundlePath,const std::string & diskPath)160 bool BundleUtil::CheckSystemSize(const std::string &bundlePath, const std::string &diskPath)
161 {
162     struct statfs diskInfo = { 0 };
163     if (statfs(diskPath.c_str(), &diskInfo) != 0) {
164         APP_LOGE("call statfs error");
165         return false;
166     }
167     int64_t freeSize = diskInfo.f_bfree * diskInfo.f_bsize;
168     APP_LOGD("left free size in the disk path is %{public}" PRId64, freeSize / Constants::ONE_GB);
169 
170     return CheckFileSize(bundlePath, freeSize);
171 }
172 
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)173 bool BundleUtil::GetHapFilesFromBundlePath(const std::string& currentBundlePath, std::vector<std::string>& hapFileList)
174 {
175     APP_LOGD("GetHapFilesFromBundlePath with path is %{private}s", currentBundlePath.c_str());
176     if (currentBundlePath.empty()) {
177         return false;
178     }
179     DIR* dir = opendir(currentBundlePath.c_str());
180     if (dir == nullptr) {
181         char errMsg[256] = {0};
182         strerror_r(errno, errMsg, sizeof(errMsg));
183         APP_LOGE("GetHapFilesFromBundlePath open bundle dir:%{private}s is failure due to %{public}s",
184             currentBundlePath.c_str(), errMsg);
185         return false;
186     }
187     std::string bundlePath = currentBundlePath;
188     if (bundlePath.back() != Constants::FILE_SEPARATOR_CHAR) {
189         bundlePath.append(Constants::PATH_SEPARATOR);
190     }
191     struct dirent *entry = nullptr;
192     while ((entry = readdir(dir)) != nullptr) {
193         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
194             continue;
195         }
196         const std::string hapFilePath = bundlePath + entry->d_name;
197         std::string realPath = "";
198         if (CheckFilePath(hapFilePath, realPath) != ERR_OK) {
199             APP_LOGE("find invalid hap path %{private}s", hapFilePath.c_str());
200             closedir(dir);
201             return false;
202         }
203         hapFileList.emplace_back(realPath);
204         APP_LOGD("find hap path %{private}s", realPath.c_str());
205 
206         if (!hapFileList.empty() && (hapFileList.size() > Constants::MAX_HAP_NUMBER)) {
207             APP_LOGE("reach the max hap number 128, stop to add more.");
208             closedir(dir);
209             return false;
210         }
211     }
212     closedir(dir);
213     return true;
214 }
215 
GetCurrentTime()216 int64_t BundleUtil::GetCurrentTime()
217 {
218     int64_t time =
219         std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
220         .count();
221     APP_LOGD("the current time is %{public}" PRId64, time);
222     return time;
223 }
224 
DeviceAndNameToKey(const std::string & deviceId,const std::string & bundleName,std::string & key)225 void BundleUtil::DeviceAndNameToKey(
226     const std::string &deviceId, const std::string &bundleName, std::string &key)
227 {
228     key.append(deviceId);
229     key.append(Constants::FILE_UNDERLINE);
230     key.append(bundleName);
231     APP_LOGD("bundleName = %{public}s", bundleName.c_str());
232 }
233 
KeyToDeviceAndName(const std::string & key,std::string & deviceId,std::string & bundleName)234 bool BundleUtil::KeyToDeviceAndName(
235     const std::string &key, std::string &deviceId, std::string &bundleName)
236 {
237     bool ret = false;
238     std::vector<std::string> splitStrs;
239     OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs);
240     // the expect split size should be 2.
241     // key rule is <deviceId>_<bundleName>
242     if (splitStrs.size() == EXPECT_SPLIT_SIZE) {
243         deviceId = splitStrs[0];
244         bundleName = splitStrs[1];
245         ret = true;
246     }
247     APP_LOGD("bundleName = %{public}s", bundleName.c_str());
248     return ret;
249 }
250 
GetUserIdByCallingUid()251 int32_t BundleUtil::GetUserIdByCallingUid()
252 {
253     int32_t uid = IPCSkeleton::GetCallingUid();
254     APP_LOGI("get calling uid(%{public}d)", uid);
255     return GetUserIdByUid(uid);
256 }
257 
GetUserIdByUid(int32_t uid)258 int32_t BundleUtil::GetUserIdByUid(int32_t uid)
259 {
260     if (uid <= Constants::INVALID_UID) {
261         APP_LOGE("uid is illegal: %{public}d", uid);
262         return Constants::INVALID_USERID;
263     }
264 
265     return uid / Constants::BASE_USER_RANGE;
266 }
267 
MakeFsConfig(const std::string & bundleName,int32_t bundleId,const std::string & configPath)268 void BundleUtil::MakeFsConfig(const std::string &bundleName, int32_t bundleId, const std::string &configPath)
269 {
270     std::string bundleDir = configPath + Constants::PATH_SEPARATOR + bundleName;
271     if (access(bundleDir.c_str(), F_OK) != 0) {
272         if (mkdir(bundleDir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
273             APP_LOGE("make bundle dir error");
274             return;
275         }
276     }
277 
278     std::string realBundleDir;
279     if (!PathToRealPath(bundleDir, realBundleDir)) {
280         APP_LOGE("bundleIdFile is not real path");
281         return;
282     }
283 
284     realBundleDir += (Constants::PATH_SEPARATOR + Constants::BUNDLE_ID_FILE);
285 
286     int32_t bundleIdFd = open(realBundleDir.c_str(), O_WRONLY | O_TRUNC);
287     if (bundleIdFd > 0) {
288         std::string bundleIdStr = std::to_string(bundleId);
289         if (write(bundleIdFd, bundleIdStr.c_str(), bundleIdStr.size()) < 0) {
290             APP_LOGE("write bundleId error");
291         }
292     }
293     close(bundleIdFd);
294 }
295 
RemoveFsConfig(const std::string & bundleName,const std::string & configPath)296 void BundleUtil::RemoveFsConfig(const std::string &bundleName, const std::string &configPath)
297 {
298     std::string bundleDir = configPath + Constants::PATH_SEPARATOR + bundleName;
299     std::string realBundleDir;
300     if (!PathToRealPath(bundleDir, realBundleDir)) {
301         APP_LOGE("bundleDir is not real path");
302         return;
303     }
304     if (rmdir(realBundleDir.c_str()) != 0) {
305         APP_LOGE("remove hmdfs bundle dir error");
306     }
307 }
308 
CreateInstallTempDir(uint32_t installerId,const DirType & type)309 std::string BundleUtil::CreateInstallTempDir(uint32_t installerId, const DirType &type)
310 {
311     std::time_t curTime = std::time(0);
312     std::string tempDir = Constants::HAP_COPY_PATH;
313     if (type == DirType::STREAM_INSTALL_DIR) {
314         tempDir += Constants::PATH_SEPARATOR + Constants::STREAM_INSTALL_PATH;
315     } else if (type == DirType::QUICK_FIX_DIR) {
316         tempDir += Constants::PATH_SEPARATOR + Constants::QUICK_FIX_PATH;
317     } else {
318         return "";
319     }
320     tempDir += Constants::PATH_SEPARATOR + std::to_string(curTime) +
321         std::to_string(installerId) + Constants::PATH_SEPARATOR;
322     if (!OHOS::ForceCreateDirectory(tempDir)) {
323         APP_LOGE("mkdir %{private}s failed", tempDir.c_str());
324         return "";
325     }
326     if (chown(tempDir.c_str(), Constants::FOUNDATION_UID, Constants::BMS_GID) != 0) {
327         APP_LOGE("fail to change %{private}s ownership", tempDir.c_str());
328         return "";
329     }
330     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
331     if (!OHOS::ChangeModeFile(tempDir, mode)) {
332         APP_LOGE("change mode failed, temp install dir : %{private}s", tempDir.c_str());
333         return "";
334     }
335     return tempDir;
336 }
337 
CreateFileDescriptor(const std::string & bundlePath,long long offset)338 int32_t BundleUtil::CreateFileDescriptor(const std::string &bundlePath, long long offset)
339 {
340     int fd = -1;
341     if (bundlePath.length() > Constants::PATH_MAX_SIZE) {
342         APP_LOGE("the length of the bundlePath exceeds maximum limitation");
343         return fd;
344     }
345     if ((fd = open(bundlePath.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH)) < 0) {
346         APP_LOGE("open bundlePath %{public}s failed", bundlePath.c_str());
347         return fd;
348     }
349     if (offset > 0) {
350         lseek(fd, offset, SEEK_SET);
351     }
352     return fd;
353 }
354 
CreateFileDescriptorForReadOnly(const std::string & bundlePath,long long offset)355 int32_t BundleUtil::CreateFileDescriptorForReadOnly(const std::string &bundlePath, long long offset)
356 {
357     int fd = -1;
358     if (bundlePath.length() > Constants::PATH_MAX_SIZE) {
359         APP_LOGE("the length of the bundlePath exceeds maximum limitation");
360         return fd;
361     }
362     std::string realPath;
363     if (!PathToRealPath(bundlePath, realPath)) {
364         APP_LOGE("file is not real path");
365         return fd;
366     }
367 
368     if ((fd = open(realPath.c_str(), O_RDONLY)) < 0) {
369         APP_LOGE("open bundlePath %{public}s failed", realPath.c_str());
370         return fd;
371     }
372     if (offset > 0) {
373         lseek(fd, offset, SEEK_SET);
374     }
375     return fd;
376 }
377 
CloseFileDescriptor(std::vector<int32_t> & fdVec)378 void BundleUtil::CloseFileDescriptor(std::vector<int32_t> &fdVec)
379 {
380     for_each(fdVec.begin(), fdVec.end(), [](const auto &fd) {
381         if (fd > 0) {
382             close(fd);
383         }
384     });
385     fdVec.clear();
386 }
387 
IsExistFile(const std::string & path)388 bool BundleUtil::IsExistFile(const std::string &path)
389 {
390     if (path.empty()) {
391         return false;
392     }
393 
394     struct stat buf = {};
395     if (stat(path.c_str(), &buf) != 0) {
396         return false;
397     }
398 
399     return S_ISREG(buf.st_mode);
400 }
401 
IsExistDir(const std::string & path)402 bool BundleUtil::IsExistDir(const std::string &path)
403 {
404     if (path.empty()) {
405         return false;
406     }
407 
408     struct stat buf = {};
409     if (stat(path.c_str(), &buf) != 0) {
410         return false;
411     }
412 
413     return S_ISDIR(buf.st_mode);
414 }
415 
RenameFile(const std::string & oldPath,const std::string & newPath)416 bool BundleUtil::RenameFile(const std::string &oldPath, const std::string &newPath)
417 {
418     if (oldPath.empty() || newPath.empty()) {
419         APP_LOGE("oldPath or newPath is empty");
420         return false;
421     }
422 
423     if (!DeleteDir(newPath)) {
424         APP_LOGE("delete newPath failed");
425         return false;
426     }
427 
428     return rename(oldPath.c_str(), newPath.c_str()) == 0;
429 }
430 
DeleteDir(const std::string & path)431 bool BundleUtil::DeleteDir(const std::string &path)
432 {
433     if (IsExistFile(path)) {
434         return OHOS::RemoveFile(path);
435     }
436 
437     if (IsExistDir(path)) {
438         return OHOS::ForceRemoveDirectory(path);
439     }
440 
441     return true;
442 }
443 
GetBoolStrVal(bool val)444 std::string BundleUtil::GetBoolStrVal(bool val)
445 {
446     return val ? "true" : "false";
447 }
448 
CopyFile(const std::string & sourceFile,const std::string & destinationFile)449 bool BundleUtil::CopyFile(
450     const std::string &sourceFile, const std::string &destinationFile)
451 {
452     if (sourceFile.empty() || destinationFile.empty()) {
453         APP_LOGE("Copy file failed due to sourceFile or destinationFile is empty");
454         return false;
455     }
456 
457     std::ifstream in(sourceFile);
458     if (!in.is_open()) {
459         APP_LOGE("Copy file failed due to open sourceFile failed");
460         return false;
461     }
462 
463     std::ofstream out(destinationFile);
464     if (!out.is_open()) {
465         APP_LOGE("Copy file failed due to open destinationFile failed");
466         in.close();
467         return false;
468     }
469 
470     out << in.rdbuf();
471     in.close();
472     out.close();
473     return true;
474 }
475 
GetResource(const std::string & bundleName,const std::string & moduleName,int32_t resId)476 Resource BundleUtil::GetResource(const std::string &bundleName, const std::string &moduleName, int32_t resId)
477 {
478     Resource resource;
479     resource.bundleName = bundleName;
480     resource.moduleName = moduleName;
481     resource.id = resId;
482     return resource;
483 }
484 
CreateDir(const std::string & dir)485 bool BundleUtil::CreateDir(const std::string &dir)
486 {
487     if (dir.empty()) {
488         APP_LOGE("path is empty");
489         return false;
490     }
491 
492     if (IsExistFile(dir)) {
493         return true;
494     }
495 
496     if (!OHOS::ForceCreateDirectory(dir)) {
497         APP_LOGE("mkdir %{public}s failed", dir.c_str());
498         return false;
499     }
500 
501     if (chown(dir.c_str(), Constants::FOUNDATION_UID, Constants::BMS_GID) != 0) {
502         APP_LOGE("fail to change %{public}s ownership", dir.c_str());
503         return false;
504     }
505 
506     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
507     if (!OHOS::ChangeModeFile(dir, mode)) {
508         APP_LOGE("change mode failed, temp install dir : %{public}s", dir.c_str());
509         return false;
510     }
511     return true;
512 }
513 
RevertToRealPath(const std::string & sandBoxPath,const std::string & bundleName,std::string & realPath)514 bool BundleUtil::RevertToRealPath(const std::string &sandBoxPath, const std::string &bundleName, std::string &realPath)
515 {
516     if (sandBoxPath.empty() || bundleName.empty() ||
517         sandBoxPath.find(Constants::SANDBOX_DATA_PATH) == std::string::npos) {
518         APP_LOGE("input sandboxPath or bundleName invalid");
519         return false;
520     }
521 
522     realPath = sandBoxPath;
523     std::string relaDataPath = Constants::REAL_DATA_PATH + Constants::PATH_SEPARATOR
524         + std::to_string(BundleUtil::GetUserIdByCallingUid()) + Constants::BASE + bundleName;
525     realPath.replace(realPath.find(Constants::SANDBOX_DATA_PATH),
526         std::string(Constants::SANDBOX_DATA_PATH).size(), relaDataPath);
527     return true;
528 }
529 
StartWith(const std::string & source,const std::string & prefix)530 bool BundleUtil::StartWith(const std::string &source, const std::string &prefix)
531 {
532     if (source.empty() || prefix.empty()) {
533         return false;
534     }
535 
536     return source.find(prefix) == 0;
537 }
538 
EndWith(const std::string & source,const std::string & suffix)539 bool BundleUtil::EndWith(const std::string &source, const std::string &suffix)
540 {
541     if (source.empty() || suffix.empty()) {
542         return false;
543     }
544 
545     auto position = source.rfind(suffix);
546     if (position == std::string::npos) {
547         return false;
548     }
549 
550     std::string suffixStr = source.substr(position);
551     return suffixStr == suffix;
552 }
553 
GetFileSize(const std::string & filePath)554 int64_t BundleUtil::GetFileSize(const std::string &filePath)
555 {
556     struct stat fileInfo = { 0 };
557     if (stat(filePath.c_str(), &fileInfo) != 0) {
558         APP_LOGE("call stat error");
559         return 0;
560     }
561     return fileInfo.st_size;
562 }
563 }  // namespace AppExecFwk
564 }  // namespace OHOS
565