• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 CODE_SIGNATURE_SUFFIX = ".sig";
36 const std::string PATH_SEPARATOR = "/";
37 constexpr int64_t ONE_GB = 1024 * 1024 * 1024;
38 constexpr int64_t MAX_HAP_SIZE = ONE_GB * 4;  // 4GB
39 constexpr int PATH_MAX_SIZE = 256;
40 const char FILE_SEPARATOR_CHAR = '/';
41 constexpr uint8_t MAX_HAP_NUMBER = 128;
42 } // namespace
43 
44 namespace OHOS {
45 namespace AppExecFwk {
CheckFilePath(const std::string & bundlePath,std::string & realPath)46 bool BundleFileUtil::CheckFilePath(const std::string &bundlePath, std::string &realPath)
47 {
48     if (!CheckFileName(bundlePath)) {
49         APP_LOGE("bundle file path invalid");
50         return false;
51     }
52     if (!CheckFileType(bundlePath, INSTALL_FILE_SUFFIX) &&
53         !CheckFileType(bundlePath, INSTALL_SHARED_FILE_SUFFIX) &&
54         !CheckFileType(bundlePath, QUICK_FIX_FILE_SUFFIX) &&
55         !CheckFileType(bundlePath, CODE_SIGNATURE_SUFFIX)) {
56         APP_LOGE("file is not hap, hsp or hqf or sig");
57         return false;
58     }
59     if (!PathToRealPath(bundlePath, realPath)) {
60         APP_LOGE("file is not real path");
61         return false;
62     }
63     if (access(realPath.c_str(), F_OK) != 0) {
64         APP_LOGE("can not access the bundle file path: %{public}s", realPath.c_str());
65         return false;
66     }
67     if (!CheckFileSize(realPath, MAX_HAP_SIZE)) {
68         APP_LOGE("file size is larger than max hap size Max size is: %{public}" PRId64, MAX_HAP_SIZE);
69         return false;
70     }
71     return true;
72 }
73 
CheckFilePath(const std::vector<std::string> & bundlePaths,std::vector<std::string> & realPaths)74 bool BundleFileUtil::CheckFilePath(const std::vector<std::string> &bundlePaths, std::vector<std::string> &realPaths)
75 {
76     // there are three cases for bundlePaths:
77     // 1. one bundle direction in the bundlePaths, some hap files under this bundle direction.
78     // 2. one hap direction in the bundlePaths.
79     // 3. some hap file directions in the bundlePaths.
80     APP_LOGD("check file path");
81     if (bundlePaths.empty()) {
82         APP_LOGE("bundle file paths invalid");
83         return false;
84     }
85 
86     if (bundlePaths.size() == 1) {
87         APP_LOGD("bundlePaths only has one element");
88         std::string bundlePath = bundlePaths.front();
89         std::string realPath = "";
90         // it is a file
91         if (CheckFilePath(bundlePaths.front(), realPath)) {
92             APP_LOGD("path is a file");
93             realPaths.emplace_back(realPath);
94             return true;
95         }
96         if (!GetHapFilesFromBundlePath(bundlePath, realPaths)) {
97             APP_LOGE("GetHapFilesFromBundlePath failed with bundlePath:%{public}s", bundlePaths.front().c_str());
98             return false;
99         }
100         return true;
101     }
102     APP_LOGD("bundlePaths has more than one element");
103     for (const std::string &bundlePath : bundlePaths) {
104         std::string realPath = "";
105         if (!CheckFilePath(bundlePath, realPath)) {
106             return false;
107         }
108         realPaths.emplace_back(realPath);
109     }
110     APP_LOGD("finish check file path");
111     return true;
112 }
113 
CheckFileType(const std::string & fileName,const std::string & extensionName)114 bool BundleFileUtil::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 BundleFileUtil::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() > 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 BundleFileUtil::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 
GetHapFilesFromBundlePath(const std::string & currentBundlePath,std::vector<std::string> & hapFileList)157 bool BundleFileUtil::GetHapFilesFromBundlePath(const std::string &currentBundlePath,
158     std::vector<std::string> &hapFileList)
159 {
160     APP_LOGD("GetHapFilesFromBundlePath with path is %{public}s", currentBundlePath.c_str());
161     if (currentBundlePath.empty()) {
162         return false;
163     }
164     DIR* dir = opendir(currentBundlePath.c_str());
165     if (dir == nullptr) {
166         char errMsg[256] = {0};
167         strerror_r(errno, errMsg, sizeof(errMsg));
168         APP_LOGE("GetHapFilesFromBundlePath open bundle dir:%{public}s is failure due to %{public}s",
169             currentBundlePath.c_str(), errMsg);
170         return false;
171     }
172     std::string bundlePath = currentBundlePath;
173     if (bundlePath.back() != FILE_SEPARATOR_CHAR) {
174         bundlePath.append(PATH_SEPARATOR);
175     }
176     struct dirent *entry = nullptr;
177     while ((entry = readdir(dir)) != nullptr) {
178         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
179             continue;
180         }
181         const std::string hapFilePath = bundlePath + entry->d_name;
182         std::string realPath = "";
183         if (!CheckFilePath(hapFilePath, realPath)) {
184             APP_LOGE("find invalid hap path %{public}s", hapFilePath.c_str());
185             closedir(dir);
186             return false;
187         }
188         hapFileList.emplace_back(realPath);
189         APP_LOGD("find hap path %{public}s", realPath.c_str());
190 
191         if (hapFileList.size() > MAX_HAP_NUMBER) {
192             APP_LOGE("reach the max hap number %{public}hhu, stop to add more.", MAX_HAP_NUMBER);
193             closedir(dir);
194             return false;
195         }
196     }
197     closedir(dir);
198     return true;
199 }
200 } // AppExecFwk
201 } // OHOS