• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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* 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("path is not a regular file or file size is too large");
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         const 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 %{public}s", errno, bundlePath.c_str());
153         return false;
154     }
155     if (!S_ISREG(fileInfo.st_mode)) {
156         APP_LOGE("path is not a regular file: %{public}s", bundlePath.c_str());
157         return false;
158     }
159     if (fileInfo.st_size > fileSize) {
160         return false;
161     }
162     return true;
163 }
164 
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)165 bool BundleFileUtil::GetHapFilesFromBundlePath(const std::string &currentBundlePath,
166     std::vector<std::string> &hapFileList)
167 {
168     APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
169     if (currentBundlePath.empty()) {
170         return false;
171     }
172     DIR* dir = opendir(currentBundlePath.c_str());
173     if (dir == nullptr) {
174         char errMsg[256] = {0};
175         strerror_r(errno, errMsg, sizeof(errMsg));
176         APP_LOGE("open %{public}s failure due to %{public}s errno %{public}d",
177             currentBundlePath.c_str(), errMsg, errno);
178         return false;
179     }
180     std::string bundlePath = currentBundlePath;
181     if (bundlePath.back() != FILE_SEPARATOR_CHAR) {
182         bundlePath.append(PATH_SEPARATOR);
183     }
184     struct dirent *entry = nullptr;
185     while ((entry = readdir(dir)) != nullptr) {
186         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
187             continue;
188         }
189         const std::string hapFilePath = bundlePath + entry->d_name;
190         std::string realPath = "";
191         if (!CheckFilePath(hapFilePath, realPath)) {
192             APP_LOGE("invalid hap path %{public}s", hapFilePath.c_str());
193             closedir(dir);
194             return false;
195         }
196         hapFileList.emplace_back(realPath);
197         APP_LOGD("find hap path %{public}s", realPath.c_str());
198 
199         if (hapFileList.size() > MAX_HAP_NUMBER) {
200             APP_LOGE("max hap number %{public}hhu, stop add", MAX_HAP_NUMBER);
201             closedir(dir);
202             return false;
203         }
204     }
205     closedir(dir);
206     return true;
207 }
208 
DeleteDir(const std::string & path)209 bool BundleFileUtil::DeleteDir(const std::string &path)
210 {
211     bool res = true;
212     if (IsExistFile(path)) {
213         res = OHOS::RemoveFile(path);
214         if (!res && errno == ENOENT) {
215             return true;
216         }
217         return res;
218     }
219     if (IsExistDir(path)) {
220         res = OHOS::ForceRemoveDirectoryBMS(path);
221         if (!res && errno == ENOENT) {
222             return true;
223         }
224         return res;
225     }
226     return true;
227 }
228 
IsExistFile(const std::string & filePath)229 bool BundleFileUtil::IsExistFile(const std::string &filePath)
230 {
231     if (filePath.empty()) {
232         return false;
233     }
234 
235     struct stat result = {};
236     if (stat(filePath.c_str(), &result) != 0) {
237         APP_LOGE("fail stat errno:%{public}d", errno);
238         return false;
239     }
240 
241     return S_ISREG(result.st_mode);
242 }
243 
IsExistDir(const std::string & dirPath)244 bool BundleFileUtil::IsExistDir(const std::string &dirPath)
245 {
246     if (dirPath.empty()) {
247         return false;
248     }
249 
250     struct stat result = {};
251     if (stat(dirPath.c_str(), &result) != 0) {
252         APP_LOGE("fail stat errno %{public}d", errno);
253         return false;
254     }
255 
256     return S_ISDIR(result.st_mode);
257 }
258 } // AppExecFwk
259 } // OHOS