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