• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "installd/installd_operator.h"
17 
18 #include <cstdio>
19 #include <dirent.h>
20 #include <fstream>
21 #include <map>
22 #include <sstream>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include "app_log_wrapper.h"
29 #include "bundle_constants.h"
30 #include "directory_ex.h"
31 
32 namespace OHOS {
33 namespace AppExecFwk {
IsExistFile(const std::string & path)34 bool InstalldOperator::IsExistFile(const std::string &path)
35 {
36     if (path.empty()) {
37         return false;
38     }
39 
40     struct stat buf = {};
41     if (stat(path.c_str(), &buf) != 0) {
42         return false;
43     }
44     return S_ISREG(buf.st_mode);
45 }
46 
IsExistDir(const std::string & path)47 bool InstalldOperator::IsExistDir(const std::string &path)
48 {
49     if (path.empty()) {
50         return false;
51     }
52 
53     struct stat buf = {};
54     if (stat(path.c_str(), &buf) != 0) {
55         return false;
56     }
57     return S_ISDIR(buf.st_mode);
58 }
59 
MkRecursiveDir(const std::string & path,bool isReadByOthers)60 bool InstalldOperator::MkRecursiveDir(const std::string &path, bool isReadByOthers)
61 {
62     if (!OHOS::ForceCreateDirectory(path)) {
63         APP_LOGE("mkdir failed");
64         return false;
65     }
66     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH;
67     mode |= (isReadByOthers ? S_IROTH : 0);
68     return OHOS::ChangeModeDirectory(path, mode);
69 }
70 
DeleteDir(const std::string & path)71 bool InstalldOperator::DeleteDir(const std::string &path)
72 {
73     if (IsExistFile(path)) {
74         return OHOS::RemoveFile(path);
75     }
76     if (IsExistDir(path)) {
77         return OHOS::ForceRemoveDirectory(path);
78     }
79     return true;
80 }
81 
ExtractFiles(const std::string & sourcePath,const std::string & targetPath,const std::string & targetSoPath,const std::string & cpuAbi)82 bool InstalldOperator::ExtractFiles(const std::string &sourcePath, const std::string &targetPath,
83     const std::string &targetSoPath, const std::string &cpuAbi)
84 {
85     BundleExtractor extractor(sourcePath);
86     if (!extractor.Init()) {
87         return false;
88     }
89     std::vector<std::string> entryNames;
90     if (!extractor.GetZipFileNames(entryNames)) {
91         return false;
92     }
93     if (entryNames.empty()) {
94         return false;
95     }
96 
97     std::string targetDir = targetPath;
98     if (targetPath.back() != Constants::PATH_SEPARATOR[0]) {
99         targetDir = targetPath + Constants::PATH_SEPARATOR;
100     }
101     for (const auto &entryName : entryNames) {
102         if (entryName.find("..") != std::string::npos) {
103             return false;
104         }
105         if (entryName.back() == Constants::PATH_SEPARATOR[0]) {
106             continue;
107         }
108         // handle native so
109         if (isNativeSo(entryName, targetSoPath, cpuAbi)) {
110             ExtractSo(extractor, entryName, targetSoPath, cpuAbi);
111             continue;
112         }
113         const std::string dir = GetPathDir(entryName);
114         std::string filePath = targetDir + dir;
115         if (!dir.empty()) {
116             if (!MkRecursiveDir(filePath, true)) {
117                 return false;
118             }
119         }
120         filePath = targetDir + entryName;
121         if (!extractor.ExtractFile(entryName, filePath)) {
122             return false;
123         }
124         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
125         if (!OHOS::ChangeModeFile(filePath, mode)) {
126             APP_LOGE("change mode failed");
127         }
128         filePath.clear();
129     }
130     return true;
131 }
132 
isNativeSo(const std::string & entryName,const std::string & targetSoPath,const std::string & cpuAbi)133 bool InstalldOperator::isNativeSo(const std::string &entryName,
134     const std::string &targetSoPath, const std::string &cpuAbi)
135 {
136     APP_LOGD("isNativeSo, entryName : %{public}s", entryName.c_str());
137     if (targetSoPath.empty()) {
138         APP_LOGD("current hap not include so");
139         return false;
140     }
141     std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
142     if (entryName.find(prefix) == std::string::npos) {
143         APP_LOGD("entryName not start with %{public}s", prefix.c_str());
144         return false;
145     }
146     size_t len = entryName.length();
147     if (len <= Constants::SO_SUFFIX_LEN) {
148         APP_LOGD("entryName length invalid");
149         return false;
150     }
151     std::string suffix = entryName.substr(len - Constants::SO_SUFFIX_LEN, len);
152     if (suffix != Constants::SO_SUFFIX) {
153         APP_LOGD("entryName suffix not .so");
154         return false;
155     }
156     APP_LOGD("find native so, entryName : %{public}s", entryName.c_str());
157     return true;
158 }
159 
ExtractSo(const BundleExtractor & extractor,const std::string & entryName,const std::string & targetSoPath,const std::string & cpuAbi)160 void InstalldOperator::ExtractSo(const BundleExtractor &extractor, const std::string &entryName,
161     const std::string &targetSoPath, const std::string &cpuAbi)
162 {
163     // create dir if not exist
164     if (!IsExistDir(targetSoPath)) {
165         if (!MkRecursiveDir(targetSoPath, true)) {
166             APP_LOGE("create targetSoPath %{public}s failed", targetSoPath.c_str());
167             return;
168         }
169     }
170     std::string prefix = Constants::LIBS + cpuAbi + Constants::PATH_SEPARATOR;
171     std::string targetSoName = entryName.substr(prefix.length());
172     std::string targetSo = targetSoPath + targetSoName;
173     bool ret = extractor.ExtractFile(entryName, targetSo);
174     if (!ret) {
175         APP_LOGE("extract so failed, entryName : %{public}s", entryName.c_str());
176         return;
177     }
178     mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
179     if (!OHOS::ChangeModeFile(targetSo, mode)) {
180         APP_LOGE("change mode failed, targetSo : %{public}s", targetSo.c_str());
181         return;
182     }
183     APP_LOGD("extract so success, targetSo : %{public}s", targetSo.c_str());
184 }
185 
RenameDir(const std::string & oldPath,const std::string & newPath)186 bool InstalldOperator::RenameDir(const std::string &oldPath, const std::string &newPath)
187 {
188     if (oldPath.empty() || oldPath.size() > PATH_MAX) {
189         APP_LOGE("oldpath error");
190         return false;
191     }
192     if (access(oldPath.c_str(), F_OK) != 0 && access(newPath.c_str(), F_OK) == 0) {
193         return true;
194     }
195     std::string realOldPath;
196     realOldPath.reserve(PATH_MAX);
197     realOldPath.resize(PATH_MAX - 1);
198     if (realpath(oldPath.c_str(), &(realOldPath[0])) == nullptr) {
199         APP_LOGE("realOldPath %{public}s", realOldPath.c_str());
200         return false;
201     }
202 
203     if (!(IsValideCodePath(realOldPath) && IsValideCodePath(newPath))) {
204         APP_LOGE("IsValideCodePath failed");
205         return false;
206     }
207     return RenameFile(realOldPath, newPath);
208 }
209 
GetPathDir(const std::string & path)210 std::string InstalldOperator::GetPathDir(const std::string &path)
211 {
212     std::size_t pos = path.rfind(Constants::PATH_SEPARATOR);
213     if (pos == std::string::npos) {
214         return std::string();
215     }
216     return path.substr(0, pos + 1);
217 }
218 
ChangeFileAttr(const std::string & filePath,const int uid,const int gid)219 bool InstalldOperator::ChangeFileAttr(const std::string &filePath, const int uid, const int gid)
220 {
221     APP_LOGD("begin to change %{private}s file attribute", filePath.c_str());
222     if (chown(filePath.c_str(), uid, gid) != 0) {
223         APP_LOGE("fail to change %{private}s ownership", filePath.c_str());
224         return false;
225     }
226     APP_LOGD("change %{private}s file attribute successfully", filePath.c_str());
227     return true;
228 }
229 
RenameFile(const std::string & oldPath,const std::string & newPath)230 bool InstalldOperator::RenameFile(const std::string &oldPath, const std::string &newPath)
231 {
232     if (oldPath.empty() || newPath.empty()) {
233         return false;
234     }
235     if (!DeleteDir(newPath)) {
236         return false;
237     }
238     return rename(oldPath.c_str(), newPath.c_str()) == 0;
239 }
240 
IsValidPath(const std::string & rootDir,const std::string & path)241 bool InstalldOperator::IsValidPath(const std::string &rootDir, const std::string &path)
242 {
243     if (rootDir.find(Constants::PATH_SEPARATOR) != 0 ||
244         rootDir.rfind(Constants::PATH_SEPARATOR) != (rootDir.size() - 1) || rootDir.find("..") != std::string::npos) {
245         return false;
246     }
247     if (path.find("..") != std::string::npos) {
248         return false;
249     }
250     return path.compare(0, rootDir.size(), rootDir) == 0;
251 }
252 
IsValideCodePath(const std::string & codePath)253 bool InstalldOperator::IsValideCodePath(const std::string &codePath)
254 {
255     if (codePath.empty()) {
256         return false;
257     }
258     return IsValidPath(Constants::BUNDLE_BASE_CODE_DIR + Constants::PATH_SEPARATOR, codePath);
259 }
260 
DeleteFiles(const std::string & dataPath)261 bool InstalldOperator::DeleteFiles(const std::string &dataPath)
262 {
263     APP_LOGD("InstalldOperator::DeleteFiles start");
264     std::string subPath;
265     bool ret = true;
266     DIR *dir = opendir(dataPath.c_str());
267     if (dir == nullptr) {
268         return false;
269     }
270     while (true) {
271         struct dirent *ptr = readdir(dir);
272         if (ptr == nullptr) {
273             break;
274         }
275         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
276             continue;
277         }
278         subPath = OHOS::IncludeTrailingPathDelimiter(dataPath) + std::string(ptr->d_name);
279         if (ptr->d_type == DT_DIR) {
280             ret = OHOS::ForceRemoveDirectory(subPath);
281         } else {
282             if (access(subPath.c_str(), F_OK) == 0) {
283                 ret = OHOS::RemoveFile(subPath);
284             }
285         }
286     }
287     closedir(dir);
288     return ret;
289 }
290 
MkOwnerDir(const std::string & path,bool isReadByOthers,const int uid,const int gid)291 bool InstalldOperator::MkOwnerDir(const std::string &path, bool isReadByOthers, const int uid, const int gid)
292 {
293     if (!MkRecursiveDir(path, isReadByOthers)) {
294         return false;
295     }
296     return ChangeFileAttr(path, uid, gid);
297 }
298 
MkOwnerDir(const std::string & path,int mode,const int uid,const int gid)299 bool InstalldOperator::MkOwnerDir(const std::string &path, int mode, const int uid, const int gid)
300 {
301     if (!OHOS::ForceCreateDirectory(path)) {
302         APP_LOGE("mkdir failed");
303         return false;
304     }
305     if (!OHOS::ChangeModeDirectory(path, mode)) {
306         return false;
307     }
308     return ChangeFileAttr(path, uid, gid);
309 }
310 
GetDiskUsage(const std::string & dir)311 int64_t InstalldOperator::GetDiskUsage(const std::string &dir)
312 {
313     if (dir.empty() || (dir.size() > Constants::PATH_MAX_SIZE)) {
314         APP_LOGE("GetDiskUsage dir path invaild");
315         return 0;
316     }
317     std::string filePath = "";
318     if (!PathToRealPath(dir, filePath)) {
319         APP_LOGE("file is not real path, file path: %{public}s", dir.c_str());
320         return 0;
321     }
322     DIR *dirPtr = opendir(filePath.c_str());
323     if (dirPtr == nullptr) {
324         APP_LOGE("GetDiskUsage open file dir:%{private}s is failure", filePath.c_str());
325         return 0;
326     }
327     if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
328         filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
329     }
330     struct dirent *entry = nullptr;
331     int64_t size = 0;
332     while ((entry = readdir(dirPtr)) != nullptr) {
333         if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
334             continue;
335         }
336         std::string path = filePath + entry->d_name;
337         std::string realPath = "";
338         if (!PathToRealPath(path, realPath)) {
339             APP_LOGE("file is not real path %{public}s", path.c_str());
340             continue;
341         }
342         struct stat fileInfo = {0};
343         if (stat(realPath.c_str(), &fileInfo) != 0) {
344             APP_LOGE("call stat error %{public}s", realPath.c_str());
345             fileInfo.st_size = 0;
346         }
347         size += fileInfo.st_size;
348         if (entry->d_type == DT_DIR) {
349             size += GetDiskUsage(realPath);
350         }
351     }
352     closedir(dirPtr);
353     return size;
354 }
355 
TraverseCacheDirectory(const std::string & currentPath,std::vector<std::string> & cacheDirs)356 void InstalldOperator::TraverseCacheDirectory(const std::string &currentPath, std::vector<std::string> &cacheDirs)
357 {
358     if (currentPath.empty() || (currentPath.size() > Constants::PATH_MAX_SIZE)) {
359         APP_LOGE("TraverseCacheDirectory current path invaild");
360         return;
361     }
362     std::string filePath = "";
363     if (!PathToRealPath(currentPath, filePath)) {
364         APP_LOGE("file is not real path, file path: %{public}s", currentPath.c_str());
365         return;
366     }
367     DIR* dir = opendir(filePath.c_str());
368     if (dir == nullptr) {
369         return;
370     }
371     if (filePath.back() != Constants::FILE_SEPARATOR_CHAR) {
372         filePath.push_back(Constants::FILE_SEPARATOR_CHAR);
373     }
374     struct dirent *ptr = nullptr;
375     while ((ptr = readdir(dir)) != nullptr) {
376         if (strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0) {
377             continue;
378         }
379         if (ptr->d_type == DT_DIR && strcmp(ptr->d_name, Constants::CACHE_DIR.c_str()) == 0) {
380             std::string currentDir = filePath + std::string(ptr->d_name);
381             cacheDirs.emplace_back(currentDir);
382             continue;
383         }
384         if (ptr->d_type == DT_DIR) {
385             std::string currentDir = filePath + std::string(ptr->d_name);
386             TraverseCacheDirectory(currentDir, cacheDirs);
387         }
388     }
389     closedir(dir);
390 }
391 
GetDiskUsageFromPath(const std::vector<std::string> & path)392 int64_t InstalldOperator::GetDiskUsageFromPath(const std::vector<std::string> &path)
393 {
394     int64_t fileSize = 0;
395     for (auto &st : path) {
396         fileSize += GetDiskUsage(st);
397     }
398     return fileSize;
399 }
400 }  // namespace AppExecFwk
401 }  // namespace OHOS