• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2025 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_file_util.h"
17 
18 #include <cerrno>
19 #include <cinttypes>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <string>
23 #include <sys/stat.h>
24 #include <sys/statfs.h>
25 #include <unistd.h>
26 
27 #include "app_log_wrapper.h"
28 #include "directory_ex.h"
29 #include "string_ex.h"
30 
31 namespace {
32 constexpr const char* INSTALL_FILE_SUFFIX = ".hap";
33 constexpr const char* HSP_FILE_SUFFIX = ".hsp";
34 constexpr const char* QUICK_FIX_FILE_SUFFIX = ".hqf";
35 constexpr const char* CODE_SIGNATURE_SUFFIX = ".sig";
36 constexpr const char* PGO_SUFFIX = ".ap";
37 constexpr const char* ABC_FILE_SUFFIX = ".abc";
38 constexpr const char* JSON_FILE_SUFFIX = ".json";
39 constexpr const char* PATH_SEPARATOR = "/";
40 constexpr int64_t ONE_GB = 1024 * 1024 * 1024;
41 constexpr int64_t MAX_HAP_SIZE = ONE_GB * 4;  // 4GB
42 constexpr int PATH_MAX_SIZE = 256;
43 const char FILE_SEPARATOR_CHAR = '/';
44 constexpr uint8_t MAX_HAP_NUMBER = 128;
45 constexpr double LOW_PARTITION_SPACE_THRESHOLD = 0.1;
46 } // namespace
47 
48 namespace OHOS {
49 namespace AppExecFwk {
CheckFilePath(const std::string & bundlePath,std::string & realPath)50 bool BundleFileUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
51 {
52     if (!CheckFileName(bundlePath)) {
53         APP_LOGE("bundle file path invalid");
54         return false;
55     }
56     if (!CheckFileType(bundlePath, INSTALL_FILE_SUFFIX) &&
57         !CheckFileType(bundlePath, HSP_FILE_SUFFIX) &&
58         !CheckFileType(bundlePath, QUICK_FIX_FILE_SUFFIX) &&
59         !CheckFileType(bundlePath, ABC_FILE_SUFFIX) &&
60         !CheckFileType(bundlePath, CODE_SIGNATURE_SUFFIX) &&
61         !CheckFileType(bundlePath, PGO_SUFFIX) &&
62         !CheckFileType(bundlePath, JSON_FILE_SUFFIX)) {
63         APP_LOGE("file is not hap, hsp or hqf or sig or ap or json");
64         return false;
65     }
66     if (!PathToRealPath(bundlePath, realPath)) {
67         APP_LOGE("file is not real path");
68         return false;
69     }
70     if (access(realPath.c_str(), F_OK) != 0) {
71         APP_LOGE("access failed path: %{public}s errno %{public}d", realPath.c_str(), errno);
72         return false;
73     }
74     if (!CheckFileSize(realPath, MAX_HAP_SIZE)) {
75         APP_LOGE("path is not a regular file or file size is too large");
76         return false;
77     }
78     return true;
79 }
80 
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)81 bool BundleFileUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
82 {
83     // there are three cases for bundlePaths:
84     // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
85     // 2. one hap direction in the bundlePaths.
86     // 3. some hap file directions in the bundlePaths.
87     APP_LOGD("check file path");
88     if (bundlePaths.empty()) {
89         APP_LOGE("bundle file paths invalid");
90         return false;
91     }
92 
93     if (bundlePaths.size() == 1) {
94         APP_LOGD("bundlePaths only has one element");
95         const std::string& bundlePath = bundlePaths.front();
96         std::string realPath = "";
97         // it is a file
98         if (CheckFilePath(bundlePaths.front(), realPath)) {
99             APP_LOGD("path is a file");
100             realPaths.emplace_back(realPath);
101             return true;
102         }
103         if (!GetHapFilesFromBundlePath(bundlePath, realPaths)) {
104             APP_LOGE("GetHapFilesFromBundlePath failed :%{public}s", bundlePaths.front().c_str());
105             return false;
106         }
107         return true;
108     }
109     APP_LOGD("bundlePaths has more than one element");
110     for (const std::string &bundlePath : bundlePaths) {
111         std::string realPath = "";
112         if (!CheckFilePath(bundlePath, realPath)) {
113             return false;
114         }
115         realPaths.emplace_back(realPath);
116     }
117     APP_LOGD("finish check file path");
118     return true;
119 }
120 
CheckFileType(const std::string & fileName,const std::string & extensionName)121 bool BundleFileUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
122 {
123     APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
124     if (!CheckFileName(fileName)) {
125         return false;
126     }
127 
128     auto position = fileName.rfind('.');
129     if (position == std::string::npos) {
130         APP_LOGE("filename no extension name");
131         return false;
132     }
133 
134     std::string suffixStr = fileName.substr(position);
135     return LowerStr(suffixStr) == extensionName;
136 }
137 
CheckFileName(const std::string & fileName)138 bool BundleFileUtil::CheckFileName(const std::string &fileName)
139 {
140     if (fileName.empty()) {
141         APP_LOGE("the file name is empty");
142         return false;
143     }
144     if (fileName.size() > PATH_MAX_SIZE) {
145         APP_LOGE("path length %{public}zu too long", fileName.size());
146         return false;
147     }
148     return true;
149 }
150 
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)151 bool BundleFileUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
152 {
153     struct stat fileInfo = { 0 };
154     if (stat(bundlePath.c_str(), &fileInfo) != 0) {
155         APP_LOGE("call stat error:%{public}d %{public}s", errno, bundlePath.c_str());
156         return false;
157     }
158     if (!S_ISREG(fileInfo.st_mode)) {
159         APP_LOGE("path is not a regular file: %{public}s", bundlePath.c_str());
160         return false;
161     }
162     if (fileInfo.st_size > fileSize) {
163         return false;
164     }
165     return true;
166 }
167 
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)168 bool BundleFileUtil::GetHapFilesFromBundlePath(const std::string &currentBundlePath,
169     std::vector<std::string> &hapFileList)
170 {
171     APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
172     if (currentBundlePath.empty()) {
173         return false;
174     }
175     DIR* dir = opendir(currentBundlePath.c_str());
176     if (dir == nullptr) {
177         char errMsg[256] = {0};
178         strerror_r(errno, errMsg, sizeof(errMsg));
179         APP_LOGE("open %{public}s failure due to %{public}s errno %{public}d",
180             currentBundlePath.c_str(), errMsg, errno);
181         return false;
182     }
183     std::string bundlePath = currentBundlePath;
184     if (bundlePath.back() != FILE_SEPARATOR_CHAR) {
185         bundlePath.append(PATH_SEPARATOR);
186     }
187     struct dirent *entry = nullptr;
188     while ((entry = readdir(dir)) != nullptr) {
189         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
190             continue;
191         }
192         const std::string hapFilePath = bundlePath + entry->d_name;
193         std::string realPath = "";
194         if (!CheckFilePath(hapFilePath, realPath)) {
195             APP_LOGE("invalid hap path %{public}s", hapFilePath.c_str());
196             closedir(dir);
197             return false;
198         }
199         hapFileList.emplace_back(realPath);
200         APP_LOGD("find hap path %{public}s", realPath.c_str());
201 
202         if (hapFileList.size() > MAX_HAP_NUMBER) {
203             APP_LOGE("max hap number %{public}hhu, stop add", MAX_HAP_NUMBER);
204             closedir(dir);
205             return false;
206         }
207     }
208     closedir(dir);
209     return true;
210 }
211 
DeleteDir(const std::string & path)212 bool BundleFileUtil::DeleteDir(const std::string &path)
213 {
214     bool res = true;
215     if (IsExistFile(path)) {
216         res = OHOS::RemoveFile(path);
217         if (!res && errno == ENOENT) {
218             return true;
219         }
220         return res;
221     }
222     if (IsExistDir(path)) {
223         res = OHOS::ForceRemoveDirectoryBMS(path);
224         if (!res && errno == ENOENT) {
225             return true;
226         }
227         return res;
228     }
229     return true;
230 }
231 
IsExistFile(const std::string & filePath)232 bool BundleFileUtil::IsExistFile(const std::string &filePath)
233 {
234     if (filePath.empty()) {
235         return false;
236     }
237 
238     struct stat result = {};
239     if (stat(filePath.c_str(), &result) != 0) {
240         APP_LOGE("fail stat errno:%{public}d", errno);
241         return false;
242     }
243 
244     return S_ISREG(result.st_mode);
245 }
246 
IsExistDir(const std::string & dirPath)247 bool BundleFileUtil::IsExistDir(const std::string &dirPath)
248 {
249     if (dirPath.empty()) {
250         return false;
251     }
252 
253     struct stat result = {};
254     if (stat(dirPath.c_str(), &result) != 0) {
255         APP_LOGE("fail stat errno %{public}d", errno);
256         return false;
257     }
258 
259     return S_ISDIR(result.st_mode);
260 }
261 
IsReportDataPartitionUsageEvent(const std::string & path)262 bool BundleFileUtil::IsReportDataPartitionUsageEvent(const std::string &path)
263 {
264     if (!IsExistDir(path)) {
265         APP_LOGD("the path %{public}s does not exist", path.c_str());
266         return false;
267     }
268 
269     struct statvfs stst;
270     if (statvfs(path.c_str(), &stst) != 0) {
271         APP_LOGE("failed to get space info for path %{public}s",
272             path.c_str());
273         return false;
274     }
275 
276     uint64_t remainPartitionTotalitySize = static_cast<uint64_t>(stst.f_blocks) * stst.f_frsize;
277     uint64_t remainPartitionFreeSize = static_cast<uint64_t>(stst.f_bavail) * stst.f_frsize;
278 
279     if (remainPartitionTotalitySize == 0) {
280         APP_LOGE("the partition %{public}s totality size is zero", path.c_str());
281         return false;
282     }
283 
284     double ratio = static_cast<double>(remainPartitionFreeSize) / remainPartitionTotalitySize;
285     if (ratio < LOW_PARTITION_SPACE_THRESHOLD) {
286         APP_LOGW("start hisysevent and partitionsize is smaller then 10%%");
287         return true;
288     }
289     return false;
290 }
291 } // AppExecFwk
292 } // OHOS