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 <sys/stat.h>
23 #include <sys/statfs.h>
24 #include <thread>
25 #include <unistd.h>
26
27 #include "app_log_wrapper.h"
28 #include "bundle_constants.h"
29 #include "bytrace.h"
30 #include "directory_ex.h"
31 #include "ipc_skeleton.h"
32 #include "string_ex.h"
33
34 namespace OHOS {
35 namespace AppExecFwk {
36 namespace {
37 const std::string::size_type EXPECT_SPLIT_SIZE = 2;
38 static std::string g_deviceUdid;
39 static std::mutex g_mutex;
40 }
41
CheckFilePath(const std::string & bundlePath,std::string & realPath)42 ErrCode BundleUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
43 {
44 if (!CheckFileName(bundlePath)) {
45 APP_LOGE("bundle file path invalid");
46 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
47 }
48 if (!CheckFileType(bundlePath, Constants::INSTALL_FILE_SUFFIX)) {
49 APP_LOGE("file is not hap");
50 return ERR_APPEXECFWK_INSTALL_INVALID_HAP_NAME;
51 }
52 if (!PathToRealPath(bundlePath, realPath)) {
53 APP_LOGE("file is not real path");
54 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
55 }
56 if (access(realPath.c_str(), F_OK) != 0) {
57 APP_LOGE("can not access the bundle file path: %{private}s", realPath.c_str());
58 return ERR_APPEXECFWK_INSTALL_INVALID_BUNDLE_FILE;
59 }
60 if (!CheckFileSize(realPath, Constants::MAX_HAP_SIZE)) {
61 APP_LOGE("file size is larger than max hap size Max size is: %{public}" PRId64, Constants::MAX_HAP_SIZE);
62 return ERR_APPEXECFWK_INSTALL_INVALID_HAP_SIZE;
63 }
64 return ERR_OK;
65 }
66
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)67 ErrCode BundleUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
68 {
69 BYTRACE_NAME(BYTRACE_TAG_APP, __PRETTY_FUNCTION__);
70 // there are three cases for bundlePaths:
71 // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
72 // 2. one hap direction in the bundlePaths.
73 // 3. some hap file directions in the bundlePaths.
74 APP_LOGD("check file path");
75 if (bundlePaths.empty()) {
76 APP_LOGE("bundle file paths invalid");
77 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
78 }
79 ErrCode ret = ERR_OK;
80
81 if (bundlePaths.size() == 1) {
82 struct stat s;
83 std::string bundlePath = bundlePaths.front();
84 std::string realPath = "";
85 if (stat(bundlePath.c_str(), &s) == 0) {
86 // it is a direction
87 if ((s.st_mode & S_IFDIR) && !GetHapFilesFromBundlePath(bundlePath, realPaths)) {
88 APP_LOGE("GetHapFilesFromBundlePath failed with bundlePath:%{private}s", bundlePaths.front().c_str());
89 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
90 }
91 // it is a file
92 if ((s.st_mode & S_IFREG) && (ret = CheckFilePath(bundlePaths.front(), realPath)) == ERR_OK) {
93 realPaths.emplace_back(realPath);
94 }
95 return ret;
96 } else {
97 APP_LOGE("bundlePath is not existed with :%{private}s", bundlePaths.front().c_str());
98 return ERR_APPEXECFWK_INSTALL_FILE_PATH_INVALID;
99 }
100 } else {
101 for (const std::string& bundlePath : bundlePaths) {
102 std::string realPath = "";
103 ret = CheckFilePath(bundlePath, realPath);
104 if (ret != ERR_OK) {
105 return ret;
106 }
107 realPaths.emplace_back(realPath);
108 }
109 }
110 APP_LOGD("finish check file path");
111 return ret;
112 }
113
CheckFileType(const std::string & fileName,const std::string & extensionName)114 bool BundleUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
115 {
116 APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
117 if (!CheckFileName(fileName)) {
118 return false;
119 }
120
121 auto position = fileName.rfind('.');
122 if (position == std::string::npos) {
123 APP_LOGE("filename no extension name");
124 return false;
125 }
126
127 std::string suffixStr = fileName.substr(position);
128 return LowerStr(suffixStr) == extensionName;
129 }
130
CheckFileName(const std::string & fileName)131 bool BundleUtil::CheckFileName(const std::string &fileName)
132 {
133 if (fileName.empty()) {
134 APP_LOGE("the file name is empty");
135 return false;
136 }
137 if (fileName.size() > Constants::PATH_MAX_SIZE) {
138 APP_LOGE("bundle file path length %{public}zu too long", fileName.size());
139 return false;
140 }
141 return true;
142 }
143
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)144 bool BundleUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
145 {
146 struct stat fileInfo = { 0 };
147 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
148 APP_LOGE("call stat error");
149 return false;
150 }
151 if (fileInfo.st_size > fileSize) {
152 return false;
153 }
154 return true;
155 }
156
CheckSystemSize(const std::string & bundlePath,const std::string & diskPath)157 bool BundleUtil::CheckSystemSize(const std::string &bundlePath, const std::string &diskPath)
158 {
159 struct statfs diskInfo = { 0 };
160 if (statfs(diskPath.c_str(), &diskInfo) != 0) {
161 APP_LOGE("call statfs error");
162 return false;
163 }
164 int64_t freeSize = diskInfo.f_bfree * diskInfo.f_bsize;
165 APP_LOGD("left free size in the disk path is %{public}" PRId64, freeSize / Constants::ONE_GB);
166
167 return CheckFileSize(bundlePath, freeSize);
168 }
169
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)170 bool BundleUtil::GetHapFilesFromBundlePath(const std::string& currentBundlePath, std::vector<std::string>& hapFileList)
171 {
172 APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
173 if (currentBundlePath.empty()) {
174 return false;
175 }
176 DIR* dir = opendir(currentBundlePath.c_str());
177 if (dir == nullptr) {
178 APP_LOGE("GetHapFilesFromBundlePath open bundle dir:%{private}s is failure", currentBundlePath.c_str());
179 return false;
180 }
181 std::string bundlePath = currentBundlePath;
182 if (bundlePath.back() != Constants::FILE_SEPARATOR_CHAR) {
183 bundlePath.append(Constants::PATH_SEPARATOR);
184 }
185 struct dirent *entry = nullptr;
186 while ((entry = readdir(dir)) != nullptr) {
187 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
188 continue;
189 }
190 const std::string hapFilePath = bundlePath + entry->d_name;
191 std::string realPath = "";
192 if (CheckFilePath(hapFilePath, realPath) != ERR_OK) {
193 APP_LOGE("find invalid hap path %{public}s", hapFilePath.c_str());
194 closedir(dir);
195 return false;
196 }
197 hapFileList.emplace_back(realPath);
198 APP_LOGD("find hap path %{public}s", realPath.c_str());
199
200 if (!hapFileList.empty() && (hapFileList.size() > Constants::MAX_HAP_NUMBER)) {
201 APP_LOGE("reach the max hap number 128, stop to add more.");
202 closedir(dir);
203 return false;
204 }
205 }
206 closedir(dir);
207 return true;
208 }
209
GetCurrentTime()210 int64_t BundleUtil::GetCurrentTime()
211 {
212 int64_t time =
213 std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
214 .count();
215 APP_LOGD("the current time is %{public}" PRId64, time);
216 return time;
217 }
218
DeviceAndNameToKey(const std::string & deviceId,const std::string & bundleName,std::string & key)219 void BundleUtil::DeviceAndNameToKey(
220 const std::string &deviceId, const std::string &bundleName, std::string &key)
221 {
222 key.append(deviceId);
223 key.append(Constants::FILE_UNDERLINE);
224 key.append(bundleName);
225 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
226 }
227
KeyToDeviceAndName(const std::string & key,std::string & deviceId,std::string & bundleName)228 bool BundleUtil::KeyToDeviceAndName(
229 const std::string &key, std::string &deviceId, std::string &bundleName)
230 {
231 bool ret = false;
232 std::vector<std::string> splitStrs;
233 OHOS::SplitStr(key, Constants::FILE_UNDERLINE, splitStrs);
234 // the expect split size should be 2.
235 // key rule is <deviceId>_<bundleName>
236 if (splitStrs.size() == EXPECT_SPLIT_SIZE) {
237 deviceId = splitStrs[0];
238 bundleName = splitStrs[1];
239 ret = true;
240 }
241 APP_LOGD("bundleName = %{public}s", bundleName.c_str());
242 return ret;
243 }
244
GetUserIdByCallingUid()245 int32_t BundleUtil::GetUserIdByCallingUid()
246 {
247 int32_t uid = IPCSkeleton::GetCallingUid();
248 APP_LOGI("get calling uid(%{public}d)", uid);
249 return GetUserIdByUid(uid);
250 }
251
GetUserIdByUid(int32_t uid)252 int32_t BundleUtil::GetUserIdByUid(int32_t uid)
253 {
254 if (uid <= Constants::INVALID_UID) {
255 APP_LOGE("uid is illegal: %{public}d", uid);
256 return Constants::INVALID_USERID;
257 }
258
259 return uid / Constants::BASE_USER_RANGE;
260 }
261
MakeHmdfsConfig(const std::string & bundleName,int32_t bundleId)262 void BundleUtil::MakeHmdfsConfig(const std::string &bundleName, int32_t bundleId)
263 {
264 std::string bundleDir = Constants::HMDFS_CONFIG_PATH + Constants::PATH_SEPERATE + bundleName;
265 if (access(bundleDir.c_str(), F_OK) != 0) {
266 if (mkdir(bundleDir.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
267 APP_LOGE("make bundle dir error");
268 return;
269 }
270 }
271
272 std::string realBundleDir;
273 if (!PathToRealPath(bundleDir, realBundleDir)) {
274 APP_LOGE("bundleIdFile is not real path");
275 return;
276 }
277
278 realBundleDir += (Constants::PATH_SEPERATE + Constants::BUNDLE_ID_FILE);
279
280 int32_t bundleIdFd = open(realBundleDir.c_str(), O_WRONLY | O_TRUNC);
281 if (bundleIdFd > 0) {
282 std::string bundleIdStr = std::to_string(bundleId);
283 if (write(bundleIdFd, bundleIdStr.c_str(), bundleIdStr.size()) < 0) {
284 APP_LOGE("write bundleId error");
285 }
286 }
287 close(bundleIdFd);
288 }
289
RemoveHmdfsConfig(const std::string & bundleName)290 void BundleUtil::RemoveHmdfsConfig(const std::string &bundleName)
291 {
292 std::string bundleDir = Constants::HMDFS_CONFIG_PATH + Constants::PATH_SEPERATE + bundleName;
293 std::string realBundleDir;
294 if (!PathToRealPath(bundleDir, realBundleDir)) {
295 APP_LOGE("bundleDir is not real path");
296 return;
297 }
298 if (rmdir(realBundleDir.c_str()) != 0) {
299 APP_LOGE("remove hmdfs bundle dir error");
300 }
301 }
302 } // namespace AppExecFwk
303 } // namespace OHOS
304