1 /*
2 * Copyright (c) 2025-2025 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 #include "file_utils.h"
16 #include <chrono>
17 #include <climits>
18 #include <fcntl.h>
19 #include <fstream>
20 #include <iostream>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include "string_utils.h"
24 #include "signature_tools_errno.h"
25
26 namespace OHOS {
27 namespace SignatureTools {
28
29 const int FileUtils::NUM_TWO = 2;
30 const int FileUtils::NUM_THREE = 3;
31 const int FileUtils::NUM_FOUR = 4;
32 const std::string FileUtils::LIBS_PATH_PREFIX = "libs/";
33 const char ELF_MAGIC[] = { '\x7f', 'E', 'L', 'F' };
IsEmpty(std::string cs)34 bool FileUtils::IsEmpty(std::string cs)
35 {
36 if (cs.length() == 0) {
37 return true;
38 }
39 return false;
40 }
41
GetSuffix(std::string filePath)42 std::string FileUtils::GetSuffix(std::string filePath)
43 {
44 if (filePath.empty()) {
45 return "";
46 }
47 size_t lastDotPosition = filePath.rfind(".");
48 bool positionFlag = (lastDotPosition == std::string::npos) || (lastDotPosition == filePath.size() - 1);
49 if (positionFlag) {
50 return "";
51 }
52 return filePath.substr(lastDotPosition + 1);
53 }
54
ValidFileType(const std::string & filePath,const std::initializer_list<std::string> types)55 bool FileUtils::ValidFileType(const std::string& filePath, const std::initializer_list<std::string> types)
56 {
57 std::string suffix = GetSuffix(filePath);
58 bool flag = suffix.empty() || (StringUtils::ContainsCase(types, suffix) == false);
59 if (flag) {
60 PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "Not support file: " + filePath);
61 return false;
62 }
63 return true;
64 }
65
Write(const std::string & content,const std::string & output)66 int FileUtils::Write(const std::string& content, const std::string& output)
67 {
68 std::ofstream outFile(output, std::ios::binary);
69 bool flag = (outFile.rdstate() != 0);
70 if (flag) {
71 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open output file: " + output + " failed");
72 return IO_ERROR;
73 }
74 outFile.write(&content[0], content.size());
75 if (outFile.rdstate() != 0) {
76 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "Failed to write data to output stream.");
77 return IO_ERROR;
78 }
79 return RET_OK;
80 }
81
Read(std::ifstream & input,std::string & ret)82 int FileUtils::Read(std::ifstream& input, std::string& ret)
83 {
84 ret.clear();
85 if (input.rdstate() != 0) {
86 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "invalid input stream");
87 return IO_ERROR;
88 }
89 ret.clear();
90 std::string buffer(FileUtils::FILE_BUFFER_BLOCK, 0);
91 while (input) {
92 input.read(&buffer[0], buffer.size());
93 if (input.fail() && !input.eof()) {
94 SIGNATURE_TOOLS_LOGE("error occurred while reading data");
95 return IO_ERROR;
96 }
97 ret.append(&buffer[0], input.gcount());
98 }
99 return RET_OK;
100 }
101
ReadFile(const std::string & path,std::string & ret)102 int FileUtils::ReadFile(const std::string& path, std::string& ret)
103 {
104 std::ifstream file(path, std::ios::binary);
105 bool flag = (file.rdstate() != 0);
106 if (flag) {
107 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open input file: " + path + " failed");
108 return IO_ERROR;
109 }
110 if (Read(file, ret) < 0) {
111 SIGNATURE_TOOLS_LOGE("read error!");
112 return IO_ERROR;
113 }
114 return RET_OK;
115 }
116
ReadFileToByteBuffer(const std::string & file,ByteBuffer & buffer)117 bool FileUtils::ReadFileToByteBuffer(const std::string& file, ByteBuffer& buffer)
118 {
119 std::string ret;
120 if (ReadFile(file, ret) < 0) {
121 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, file + " not exist or can not read!");
122 return false;
123 }
124 buffer.SetCapacity(static_cast<int32_t>(ret.size()));
125 buffer.PutData(ret.data(), ret.size());
126 return true;
127 }
128
isElfFile(const std::string & filePath)129 bool FileUtils::isElfFile(const std::string& filePath)
130 {
131 char magic[sizeof(ELF_MAGIC)];
132 std::ifstream file(filePath, std::ios::binary);
133 if (!file) {
134 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open input file: " + filePath + " failed");
135 return false;
136 }
137 file.read(magic, sizeof(ELF_MAGIC));
138 return std::equal(magic, magic + sizeof(ELF_MAGIC), ELF_MAGIC);
139 }
140
ReadFileByOffsetAndLength(std::ifstream & file,size_t offset,size_t length,std::string & ret)141 int FileUtils::ReadFileByOffsetAndLength(std::ifstream& file, size_t offset, size_t length, std::string& ret)
142 {
143 if (length > INT_MAX) {
144 SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length);
145 return RET_FAILED;
146 }
147 if (ReadInputByOffsetAndLength(file, offset, length, ret) < 0) {
148 SIGNATURE_TOOLS_LOGE("Error readInputByOffsetAndLength");
149 return IO_ERROR;
150 }
151 return RET_OK;
152 }
153
ReadInputByOffsetAndLength(std::ifstream & input,size_t offset,size_t length,std::string & ret)154 int FileUtils::ReadInputByOffsetAndLength(std::ifstream& input, size_t offset, size_t length, std::string& ret)
155 {
156 if (length > INT_MAX) {
157 SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length);
158 return -1;
159 }
160 input.seekg(offset);
161 if (ReadInputByLength(input, length, ret) < 0) {
162 SIGNATURE_TOOLS_LOGE("Error readInputByLength");
163 return -1;
164 }
165 return RET_OK;
166 }
167
ReadInputByLength(std::ifstream & input,size_t length,std::string & ret)168 int FileUtils::ReadInputByLength(std::ifstream& input, size_t length, std::string& ret)
169 {
170 if (length > INT_MAX) {
171 SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length);
172 return -1;
173 }
174 if (input.rdstate() != 0) {
175 SIGNATURE_TOOLS_LOGE("Error input");
176 return -1;
177 }
178 ret.clear();
179
180 char* buffer = new (std::nothrow)char[FILE_BUFFER_BLOCK];
181 if (buffer == NULL) {
182 SIGNATURE_TOOLS_LOGE("create buffer error!");
183 return -1;
184 }
185 size_t hasReadLen = 0;
186
187 while (hasReadLen < length && input) {
188 int readLen = static_cast<int>(std::min(length - hasReadLen, (size_t)FILE_BUFFER_BLOCK));
189 input.read(buffer, readLen);
190 bool flag = (input.gcount() != readLen);
191 if (flag) {
192 delete[] buffer;
193 SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length);
194 return -1;
195 }
196 ret.append(buffer, readLen);
197 hasReadLen += readLen;
198 }
199 delete[] buffer;
200 if (hasReadLen != length) {
201 SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length);
202 return -1;
203 }
204 return RET_OK;
205 }
206
WriteInputToOutPut(std::ifstream & input,std::ofstream & output,size_t length)207 int FileUtils::WriteInputToOutPut(std::ifstream& input, std::ofstream& output, size_t length)
208 {
209 int result = RET_OK;
210 char* buf = new (std::nothrow)char[FILE_BUFFER_BLOCK];
211 if (buf == NULL) {
212 SIGNATURE_TOOLS_LOGE("create buffer error!");
213 return RET_FAILED;
214 }
215
216 while (input) {
217 int min = std::min(static_cast<int>(length), FILE_BUFFER_BLOCK);
218 input.read(buf, min);
219 if (input.fail() && !input.eof()) {
220 SIGNATURE_TOOLS_LOGE("read error!");
221 delete[] buf;
222 return IO_ERROR;
223 }
224 length -= input.gcount();
225 output.write(buf, input.gcount());
226 if (!output.good()) {
227 SIGNATURE_TOOLS_LOGE("write error!");
228 delete[] buf;
229 return IO_ERROR;
230 }
231
232 if (length <= 0) {
233 break;
234 }
235 }
236 delete[] buf;
237 // After the file is written, datasize must be 0, so the if condition will never hold
238 if (length != 0) {
239 SIGNATURE_TOOLS_LOGE("written length error!");
240 return IO_ERROR;
241 }
242 return result;
243 }
244
WriteInputToOutPut(const std::string & input,const std::string & output)245 bool FileUtils::WriteInputToOutPut(const std::string& input, const std::string& output)
246 {
247 std::ifstream in(input, std::ios::binary);
248 std::ofstream out(output, std::ios::binary);
249 bool flag = (in.rdstate() != 0);
250 if (flag) {
251 SIGNATURE_TOOLS_LOGE("Failed to get input stream object!");
252 return false;
253 }
254 flag = (out.rdstate() != 0);
255 if (flag) {
256 SIGNATURE_TOOLS_LOGE("Failed to get output stream object!");
257 return false;
258 }
259 char* buffer = new char[FILE_BUFFER_BLOCK];
260 while (!in.eof()) {
261 in.read(buffer, FILE_BUFFER_BLOCK);
262
263 if (in.fail() && !in.eof()) {
264 SIGNATURE_TOOLS_LOGE("error occurred while reading data");
265 delete[]buffer;
266 return false;
267 }
268
269 std::streamsize readLen = in.gcount();
270 if (readLen > 0) {
271 out.write(buffer, readLen);
272 }
273
274 if (!out) {
275 SIGNATURE_TOOLS_LOGE("error occurred while writing data");
276 delete[]buffer;
277 return false;
278 }
279 }
280 delete[]buffer;
281 return true;
282 }
283
IsRunnableFile(const std::string & name)284 bool FileUtils::IsRunnableFile(const std::string& name)
285 {
286 if (name.empty()) {
287 return false;
288 }
289 size_t dotPos = name.rfind('.');
290 if (dotPos == std::string::npos) {
291 return false;
292 }
293 std::string suffix = name.substr(dotPos + 1);
294 if (suffix == "an" || suffix == "abc") {
295 return true;
296 }
297 std::string libDir = name.substr(0, LIBS_PATH_PREFIX.size());
298 if (LIBS_PATH_PREFIX.compare(libDir) == 0) {
299 return true;
300 }
301 return false;
302 }
303
IsValidFile(std::string file)304 bool FileUtils::IsValidFile(std::string file)
305 {
306 struct stat fileStat;
307 bool flag = (stat(file.c_str(), &fileStat) == 0);
308 if (!flag) {
309 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + file + "' file is not exists");
310 return false;
311 }
312 flag = S_ISDIR(fileStat.st_mode);
313 if (flag) {
314 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + file + "' file is a directory not file");
315 return false;
316 }
317 SIGNATURE_TOOLS_LOGI("IsValidFile check pass %s", file.c_str());
318 return true;
319 }
320
CopyTmpFileAndDel(const std::string & tmpFile,const std::string & output)321 bool FileUtils::CopyTmpFileAndDel(const std::string& tmpFile, const std::string& output)
322 {
323 if (tmpFile == output) {
324 return true;
325 }
326 std::ifstream src(tmpFile, std::ios::binary);
327 if (!src) {
328 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + tmpFile + "' open failed");
329 return false;
330 }
331 std::ofstream dst(output, std::ios::binary);
332 if (!dst) {
333 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + output + "' open failed");
334 return false;
335 }
336 SIGNATURE_TOOLS_LOGI("CopyTmpFileAndDel from %s to %s", tmpFile.c_str(), output.c_str());
337 dst << src.rdbuf();
338
339 if (unlink(tmpFile.c_str()) != 0) {
340 SIGNATURE_TOOLS_LOGE("Error: remove tmpFile");
341 return false;
342 }
343 SIGNATURE_TOOLS_LOGI("CopyTmpFileAndDel finish");
344 return true;
345 }
346 } // namespace SignatureTools
347 } // namespace OHOS