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