1 /*
2 * Copyright (c) 2022-2024 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 const char* INSTALL_FILE_SUFFIX = ".hap";
33 const char* HSP_FILE_SUFFIX = ".hsp";
34 const char* QUICK_FIX_FILE_SUFFIX = ".hqf";
35 const char* CODE_SIGNATURE_SUFFIX = ".sig";
36 const char* PGO_SUFFIX = ".ap";
37 const char* ABC_FILE_SUFFIX = ".abc";
38 const char* PATH_SEPARATOR = "/";
39 constexpr int64_t ONE_GB = 1024 * 1024 * 1024;
40 constexpr int64_t MAX_HAP_SIZE = ONE_GB * 4; // 4GB
41 constexpr int PATH_MAX_SIZE = 256;
42 const char FILE_SEPARATOR_CHAR = '/';
43 constexpr uint8_t MAX_HAP_NUMBER = 128;
44 } // namespace
45
46 namespace OHOS {
47 namespace AppExecFwk {
CheckFilePath(const std::string & bundlePath,std::string & realPath)48 bool BundleFileUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
49 {
50 if (!CheckFileName(bundlePath)) {
51 APP_LOGE("bundle file path invalid");
52 return false;
53 }
54 if (!CheckFileType(bundlePath, INSTALL_FILE_SUFFIX) &&
55 !CheckFileType(bundlePath, HSP_FILE_SUFFIX) &&
56 !CheckFileType(bundlePath, QUICK_FIX_FILE_SUFFIX) &&
57 !CheckFileType(bundlePath, ABC_FILE_SUFFIX) &&
58 !CheckFileType(bundlePath, CODE_SIGNATURE_SUFFIX) &&
59 !CheckFileType(bundlePath, PGO_SUFFIX)) {
60 APP_LOGE("file is not hap, hsp or hqf or sig or ap");
61 return false;
62 }
63 if (!PathToRealPath(bundlePath, realPath)) {
64 APP_LOGE("file is not real path");
65 return false;
66 }
67 if (access(realPath.c_str(), F_OK) != 0) {
68 APP_LOGE("access failed path: %{public}s errno %{public}d", realPath.c_str(), errno);
69 return false;
70 }
71 if (!CheckFileSize(realPath, MAX_HAP_SIZE)) {
72 APP_LOGE("file size larger than max hap size: %{public}" PRId64, MAX_HAP_SIZE);
73 return false;
74 }
75 return true;
76 }
77
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)78 bool BundleFileUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
79 {
80 // there are three cases for bundlePaths:
81 // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
82 // 2. one hap direction in the bundlePaths.
83 // 3. some hap file directions in the bundlePaths.
84 APP_LOGD("check file path");
85 if (bundlePaths.empty()) {
86 APP_LOGE("bundle file paths invalid");
87 return false;
88 }
89
90 if (bundlePaths.size() == 1) {
91 APP_LOGD("bundlePaths only has one element");
92 std::string bundlePath = bundlePaths.front();
93 std::string realPath = "";
94 // it is a file
95 if (CheckFilePath(bundlePaths.front(), realPath)) {
96 APP_LOGD("path is a file");
97 realPaths.emplace_back(realPath);
98 return true;
99 }
100 if (!GetHapFilesFromBundlePath(bundlePath, realPaths)) {
101 APP_LOGE("GetHapFilesFromBundlePath failed :%{public}s", bundlePaths.front().c_str());
102 return false;
103 }
104 return true;
105 }
106 APP_LOGD("bundlePaths has more than one element");
107 for (const std::string &bundlePath : bundlePaths) {
108 std::string realPath = "";
109 if (!CheckFilePath(bundlePath, realPath)) {
110 return false;
111 }
112 realPaths.emplace_back(realPath);
113 }
114 APP_LOGD("finish check file path");
115 return true;
116 }
117
CheckFileType(const std::string & fileName,const std::string & extensionName)118 bool BundleFileUtil::CheckFileType(const std::string &fileName, const std::string &extensionName)
119 {
120 APP_LOGD("path is %{public}s, support suffix is %{public}s", fileName.c_str(), extensionName.c_str());
121 if (!CheckFileName(fileName)) {
122 return false;
123 }
124
125 auto position = fileName.rfind('.');
126 if (position == std::string::npos) {
127 APP_LOGE("filename no extension name");
128 return false;
129 }
130
131 std::string suffixStr = fileName.substr(position);
132 return LowerStr(suffixStr) == extensionName;
133 }
134
CheckFileName(const std::string & fileName)135 bool BundleFileUtil::CheckFileName(const std::string &fileName)
136 {
137 if (fileName.empty()) {
138 APP_LOGE("the file name is empty");
139 return false;
140 }
141 if (fileName.size() > PATH_MAX_SIZE) {
142 APP_LOGE("path length %{public}zu too long", fileName.size());
143 return false;
144 }
145 return true;
146 }
147
CheckFileSize(const std::string & bundlePath,const int64_t fileSize)148 bool BundleFileUtil::CheckFileSize(const std::string &bundlePath, const int64_t fileSize)
149 {
150 struct stat fileInfo = { 0 };
151 if (stat(bundlePath.c_str(), &fileInfo) != 0) {
152 APP_LOGE("call stat error:%{public}d", errno);
153 return false;
154 }
155 if (fileInfo.st_size > fileSize) {
156 return false;
157 }
158 return true;
159 }
160
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)161 bool BundleFileUtil::GetHapFilesFromBundlePath(const std::string ¤tBundlePath,
162 std::vector<std::string> &hapFileList)
163 {
164 APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
165 if (currentBundlePath.empty()) {
166 return false;
167 }
168 DIR* dir = opendir(currentBundlePath.c_str());
169 if (dir == nullptr) {
170 char errMsg[256] = {0};
171 strerror_r(errno, errMsg, sizeof(errMsg));
172 APP_LOGE("open %{public}s failure due to %{public}s errno %{public}d",
173 currentBundlePath.c_str(), errMsg, errno);
174 return false;
175 }
176 std::string bundlePath = currentBundlePath;
177 if (bundlePath.back() != FILE_SEPARATOR_CHAR) {
178 bundlePath.append(PATH_SEPARATOR);
179 }
180 struct dirent *entry = nullptr;
181 while ((entry = readdir(dir)) != nullptr) {
182 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
183 continue;
184 }
185 const std::string hapFilePath = bundlePath + entry->d_name;
186 std::string realPath = "";
187 if (!CheckFilePath(hapFilePath, realPath)) {
188 APP_LOGE("invalid hap path %{public}s", hapFilePath.c_str());
189 closedir(dir);
190 return false;
191 }
192 hapFileList.emplace_back(realPath);
193 APP_LOGD("find hap path %{public}s", realPath.c_str());
194
195 if (hapFileList.size() > MAX_HAP_NUMBER) {
196 APP_LOGE("max hap number %{public}hhu, stop add", MAX_HAP_NUMBER);
197 closedir(dir);
198 return false;
199 }
200 }
201 closedir(dir);
202 return true;
203 }
204
DeleteDir(const std::string & path)205 bool BundleFileUtil::DeleteDir(const std::string &path)
206 {
207 if (IsExistFile(path)) {
208 return OHOS::RemoveFile(path);
209 }
210
211 if (IsExistDir(path)) {
212 return OHOS::ForceRemoveDirectory(path);
213 }
214
215 return true;
216 }
217
IsExistFile(const std::string & filePath)218 bool BundleFileUtil::IsExistFile(const std::string &filePath)
219 {
220 if (filePath.empty()) {
221 return false;
222 }
223
224 struct stat result = {};
225 if (stat(filePath.c_str(), &result) != 0) {
226 APP_LOGE("fail stat errno:%{public}d", errno);
227 return false;
228 }
229
230 return S_ISREG(result.st_mode);
231 }
232
IsExistDir(const std::string & dirPath)233 bool BundleFileUtil::IsExistDir(const std::string &dirPath)
234 {
235 if (dirPath.empty()) {
236 return false;
237 }
238
239 struct stat result = {};
240 if (stat(dirPath.c_str(), &result) != 0) {
241 APP_LOGE("fail stat errno %{public}d", errno);
242 return false;
243 }
244
245 return S_ISDIR(result.st_mode);
246 }
247 } // AppExecFwk
248 } // OHOS