1 /*
2 * Copyright (c) 2021 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 "installd/installd_operator.h"
17
18 #include <cstdio>
19 #include <fstream>
20 #include <map>
21 #include <sstream>
22 #include <dirent.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include "directory_ex.h"
29 #include "app_log_wrapper.h"
30 #include "bundle_constants.h"
31 #include "bundle_extractor.h"
32
33 namespace OHOS {
34 namespace AppExecFwk {
35 namespace {} // namespace
36
IsExistFile(const std::string & path)37 bool InstalldOperator::IsExistFile(const std::string &path)
38 {
39 if (path.empty()) {
40 return false;
41 }
42
43 struct stat buf = {};
44 if (stat(path.c_str(), &buf) != 0) {
45 return false;
46 }
47 return S_ISREG(buf.st_mode);
48 }
49
IsExistDir(const std::string & path)50 bool InstalldOperator::IsExistDir(const std::string &path)
51 {
52 if (path.empty()) {
53 return false;
54 }
55
56 struct stat buf = {};
57 if (stat(path.c_str(), &buf) != 0) {
58 return false;
59 }
60 return S_ISDIR(buf.st_mode);
61 }
62
MkRecursiveDir(const std::string & path,bool isReadByOthers)63 bool InstalldOperator::MkRecursiveDir(const std::string &path, bool isReadByOthers)
64 {
65 if (!OHOS::ForceCreateDirectory(path)) {
66 APP_LOGE("mkdir failed");
67 return false;
68 }
69 mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH;
70 mode |= (isReadByOthers ? S_IROTH : 0);
71 return OHOS::ChangeModeDirectory(path, mode);
72 }
73
DeleteDir(const std::string & path)74 bool InstalldOperator::DeleteDir(const std::string &path)
75 {
76 if (IsExistFile(path)) {
77 return OHOS::RemoveFile(path);
78 }
79 if (IsExistDir(path)) {
80 return OHOS::ForceRemoveDirectory(path);
81 }
82 return true;
83 }
84
ExtractFiles(const std::string & sourcePath,const std::string & targetPath)85 bool InstalldOperator::ExtractFiles(const std::string &sourcePath, const std::string &targetPath)
86 {
87 BundleExtractor extractor(sourcePath);
88 if (!extractor.Init()) {
89 return false;
90 }
91 std::vector<std::string> entryNames;
92 if (!extractor.GetZipFileNames(entryNames)) {
93 return false;
94 }
95 if (entryNames.empty()) {
96 return false;
97 }
98
99 std::string targetDir = targetPath;
100 if (targetPath.back() != Constants::PATH_SEPARATOR[0]) {
101 targetDir = targetPath + Constants::PATH_SEPARATOR;
102 }
103 for (const auto &entryName : entryNames) {
104 if (entryName.find("..") != std::string::npos) {
105 return false;
106 }
107 if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
108 continue;
109 }
110 const std::string dir = GetPathDir(entryName);
111 std::string filePath = targetDir + dir;
112 if (!dir.empty()) {
113 if (!MkRecursiveDir(filePath, true)) {
114 return false;
115 }
116 }
117 filePath = targetDir + entryName;
118 if (!extractor.ExtractFile(entryName, filePath)) {
119 return false;
120 }
121 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
122 if (!OHOS::ChangeModeFile(filePath, mode)) {
123 APP_LOGE("change mode failed");
124 }
125 filePath.clear();
126 }
127 return true;
128 }
129
RenameDir(const std::string & oldPath,const std::string & newPath)130 bool InstalldOperator::RenameDir(const std::string &oldPath, const std::string &newPath)
131 {
132 if (oldPath.empty() || oldPath.size() > PATH_MAX) {
133 APP_LOGE("oldpath error");
134 return false;
135 }
136 std::string realOldPath;
137 realOldPath.reserve(PATH_MAX);
138 realOldPath.resize(PATH_MAX - 1);
139 if (realpath(oldPath.c_str(), &(realOldPath[0])) == nullptr) {
140 APP_LOGE("realOldPath %{public}s", realOldPath.c_str());
141 return false;
142 }
143 if (!(IsValideCodePath(realOldPath) && IsValideCodePath(newPath))) {
144 APP_LOGE("IsValideCodePath failed");
145 return false;
146 }
147 return RenameFile(realOldPath, newPath);
148 }
149
GetPathDir(const std::string & path)150 std::string InstalldOperator::GetPathDir(const std::string &path)
151 {
152 std::size_t pos = path.rfind(Constants::PATH_SEPARATOR);
153 if (pos == std::string::npos) {
154 return std::string();
155 }
156 return path.substr(0, pos + 1);
157 }
158
ChangeFileAttr(const std::string & filePath,const int uid,const int gid)159 bool InstalldOperator::ChangeFileAttr(const std::string &filePath, const int uid, const int gid)
160 {
161 APP_LOGD("begin to change %{private}s file attribute", filePath.c_str());
162 if (chown(filePath.c_str(), uid, gid) != 0) {
163 APP_LOGE("fail to change %{private}s ownership", filePath.c_str());
164 return false;
165 }
166 APP_LOGD("change %{private}s file attribute successfully", filePath.c_str());
167 return true;
168 }
169
RenameFile(const std::string & oldPath,const std::string & newPath)170 bool InstalldOperator::RenameFile(const std::string &oldPath, const std::string &newPath)
171 {
172 if (oldPath.empty() || newPath.empty()) {
173 return false;
174 }
175 if (!DeleteDir(newPath)) {
176 return false;
177 }
178 return rename(oldPath.c_str(), newPath.c_str()) == 0;
179 }
180
IsValidPath(const std::string & rootDir,const std::string & path)181 bool InstalldOperator::IsValidPath(const std::string &rootDir, const std::string &path)
182 {
183 if (rootDir.find(Constants::PATH_SEPARATOR) != 0 ||
184 rootDir.rfind(Constants::PATH_SEPARATOR) != (rootDir.size() - 1) || rootDir.find("..") != std::string::npos) {
185 return false;
186 }
187 if (path.find("..") != std::string::npos) {
188 return false;
189 }
190 return path.compare(0, rootDir.size(), rootDir) == 0;
191 }
192
IsValideCodePath(const std::string & codePath)193 bool InstalldOperator::IsValideCodePath(const std::string &codePath)
194 {
195 if (codePath.empty()) {
196 return false;
197 }
198 return IsValidPath(Constants::THIRD_PARTY_APP_INSTALL_PATH + Constants::PATH_SEPARATOR, codePath) ||
199 IsValidPath(Constants::SYSTEM_APP_INSTALL_PATH + Constants::PATH_SEPARATOR, codePath);
200 }
201
DeleteFiles(const std::string & dataPath)202 bool InstalldOperator::DeleteFiles(const std::string &dataPath)
203 {
204 std::string subPath;
205 bool ret = true;
206 DIR *dir = opendir(dataPath.c_str());
207 if (dir == nullptr) {
208 return false;
209 }
210 while (true) {
211 struct dirent *ptr = readdir(dir);
212 if (ptr == nullptr) {
213 break;
214 }
215 if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
216 continue;
217 }
218 subPath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name);
219 if (ptr->d_type == DT_DIR) {
220 ret = OHOS::ForceRemoveDirectory(subPath);
221 } else {
222 if (access(subPath.c_str(), F_OK) == 0) {
223 ret = OHOS::RemoveFile(subPath);
224 }
225 }
226 }
227 closedir(dir);
228 return ret;
229 }
230
MkOwnerDir(const std::string & path,bool isReadByOthers,const int uid,const int gid)231 bool InstalldOperator::MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid)
232 {
233 if (!MkRecursiveDir(path, isReadByOthers)) {
234 return false;
235 }
236 return ChangeFileAttr(path, uid, gid);
237 }
238
239 } // namespace AppExecFwk
240 } // namespace OHOS