1 /*
2 * Copyright (c) 2023 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 "module_utils.h"
17
18 #include <cerrno>
19 #include <cstdio>
20 #include <dirent.h>
21 #include <sys/stat.h>
22 #include <thread>
23
24 #include "directory_ex.h"
25 #include "log/log.h"
26 #include "module_constants.h"
27
28 namespace OHOS {
29 namespace SysInstaller {
30 using namespace Updater;
31
32 namespace {
33 constexpr std::chrono::milliseconds WAIT_FOR_FILE_TIME(5);
34 constexpr uint32_t BYTE_SIZE = 8;
35 constexpr const char *PREFIXES[] = {UPDATE_INSTALL_DIR, UPDATE_ACTIVE_DIR, UPDATE_BACKUP_DIR, MODULE_PREINSTALL_DIR};
36 }
37
CreateDirIfNeeded(const std::string & path,mode_t mode)38 bool CreateDirIfNeeded(const std::string &path, mode_t mode)
39 {
40 struct stat statData;
41
42 if (stat(path.c_str(), &statData) != 0) {
43 if (errno == ENOENT) {
44 if (mkdir(path.c_str(), mode) != 0) {
45 LOG(ERROR) << "Could not mkdir " << path;
46 return false;
47 }
48 } else {
49 LOG(ERROR) << "Could not stat " << path;
50 return false;
51 }
52 } else {
53 if (!S_ISDIR(statData.st_mode)) {
54 LOG(ERROR) << path << " exists and is not a directory";
55 return false;
56 }
57 }
58
59 // Need to manually call chmod because mkdir will create a folder with
60 // permissions mode & ~umask.
61 if (chmod(path.c_str(), mode) != 0) {
62 LOG(ERROR) << "Could not chmod " << path;
63 return false;
64 }
65 return true;
66 }
67
CheckPathExists(const std::string & path)68 bool CheckPathExists(const std::string &path)
69 {
70 struct stat buffer;
71 return stat(path.c_str(), &buffer) == 0;
72 }
73
CheckFileSuffix(const std::string & file,const std::string & suffix)74 bool CheckFileSuffix(const std::string &file, const std::string &suffix)
75 {
76 std::size_t pos = file.find_last_of('.');
77 if (pos == std::string::npos) {
78 LOG(ERROR) << "Invalid file name " << file;
79 return false;
80 }
81 std::string fileSuffix = file.substr(pos);
82 return fileSuffix == suffix;
83 }
84
GetFileName(const std::string & file)85 std::string GetFileName(const std::string &file)
86 {
87 std::size_t startPos = file.find_last_of('/') + 1;
88 std::size_t endPos = file.find_last_of('.');
89 return file.substr(startPos, endPos - startPos);
90 }
91
92 // Get hmpName from path such as "/data/module_update_package/hmpName/sa1.zip"
GetHmpName(const std::string & filePath)93 std::string GetHmpName(const std::string &filePath)
94 {
95 std::size_t endPos = filePath.find_last_of('/');
96 if (endPos == std::string::npos) {
97 LOG(ERROR) << "Invalid package path " << filePath;
98 return "";
99 }
100
101 std::size_t startPos = 0;
102 for (auto &iter : PREFIXES) {
103 if (StartsWith(filePath, iter)) {
104 startPos = strlen(iter) + 1;
105 break;
106 }
107 }
108 if (startPos == 0 || startPos >= endPos) {
109 LOG(ERROR) << "Invalid package path " << filePath;
110 return "";
111 }
112 return filePath.substr(startPos, endPos - startPos);
113 }
114
WaitForFile(const std::string & path,const std::chrono::nanoseconds & timeout)115 bool WaitForFile(const std::string &path, const std::chrono::nanoseconds &timeout)
116 {
117 Timer timer;
118 bool hasSlept = false;
119 while (timer.duration() < timeout) {
120 struct stat buffer;
121 if (stat(path.c_str(), &buffer) != -1) {
122 if (hasSlept) {
123 LOG(INFO) << "wait for '" << path << "' took " << timer;
124 }
125 return true;
126 }
127 std::this_thread::sleep_for(WAIT_FOR_FILE_TIME);
128 hasSlept = true;
129 }
130 LOG(ERROR) << "wait for '" << path << "' timed out and took " << timer;
131 return false;
132 }
133
StartsWith(const std::string & str,const std::string & prefix)134 bool StartsWith(const std::string &str, const std::string &prefix)
135 {
136 return str.substr(0, prefix.size()) == prefix;
137 }
138
ReadFullyAtOffset(int fd,uint8_t * data,size_t count,off_t offset)139 bool ReadFullyAtOffset(int fd, uint8_t *data, size_t count, off_t offset)
140 {
141 while (count > 0) {
142 ssize_t readSize = pread(fd, data, count, offset);
143 if (readSize <= 0) {
144 return false;
145 }
146 data += readSize;
147 count -= static_cast<size_t>(readSize);
148 offset += readSize;
149 }
150 return true;
151 }
152
ReadLE16(const uint8_t * buff)153 uint16_t ReadLE16(const uint8_t *buff)
154 {
155 if (buff == nullptr) {
156 LOG(ERROR) << "buff is null";
157 return 0;
158 }
159 uint16_t value16 = buff[0];
160 value16 += static_cast<uint16_t>(buff[1] << BYTE_SIZE);
161 return value16;
162 }
163
ReadLE32(const uint8_t * buff)164 uint32_t ReadLE32(const uint8_t *buff)
165 {
166 if (buff == nullptr) {
167 LOG(ERROR) << "buff is null";
168 return 0;
169 }
170 uint16_t low = ReadLE16(buff);
171 uint16_t high = ReadLE16(buff + sizeof(uint16_t));
172 uint32_t value = ((static_cast<uint32_t>(high)) << (BYTE_SIZE * sizeof(uint16_t))) | low;
173 return value;
174 }
175
operator <<(std::ostream & os,const Timer & timer)176 std::ostream &operator<<(std::ostream &os, const Timer &timer)
177 {
178 os << timer.duration().count() << "ms";
179 return os;
180 }
181
GetRealPath(const std::string & filePath)182 std::string GetRealPath(const std::string &filePath)
183 {
184 char path[PATH_MAX] = {'\0'};
185 if (realpath(filePath.c_str(), path) == nullptr) {
186 LOG(ERROR) << "get real path fail " << filePath;
187 return "";
188 }
189 if (!CheckPathExists(path)) {
190 LOG(ERROR) << "path " << path << " doesn't exist";
191 return "";
192 }
193 std::string realPath(path);
194 return realPath;
195 }
196 } // namespace SysInstaller
197 } // namespace OHOS