1 /*
2 * Copyright (c) 2024-2024 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 <iostream>
16 #include <filesystem>
17 #include <fstream>
18 #include <climits>
19
20 #include "string_utils.h"
21 #include "signature_tools_errno.h"
22 #include "file_utils.h"
23
24 namespace OHOS {
25 namespace SignatureTools {
26 namespace fs = std::filesystem;
27
28 const int FileUtils::NUM_TWO = 2;
29 const int FileUtils::NUM_THREE = 3;
30 const int FileUtils::NUM_FOUR = 4;
31 const std::string FileUtils::LIBS_PATH_PREFIX = "libs/";
IsEmpty(std::string cs)32 bool FileUtils::IsEmpty(std::string cs)
33 {
34 if (cs.length() == 0) {
35 return true;
36 }
37 return false;
38 }
39
IsSpaceEnough(const std::string & filePath,const int64_t requiredSpace)40 bool FileUtils::IsSpaceEnough(const std::string& filePath, const int64_t requiredSpace)
41 {
42 uint64_t freeSpace = 0;
43 struct statfs diskStatfs;
44 int ret = statfs(filePath.c_str(), &diskStatfs);
45 if (ret >= 0) {
46 freeSpace = (uint64_t)diskStatfs.f_bsize * (uint64_t)diskStatfs.f_bavail;
47 } else {
48 SIGNATURE_TOOLS_LOGE("statfs fail, error code = %d", ret);
49 }
50 return freeSpace >= static_cast<uint64_t>(requiredSpace);
51 }
52
GetSuffix(std::string filePath)53 std::string FileUtils::GetSuffix(std::string filePath)
54 {
55 if (filePath.empty()) {
56 return "";
57 }
58 size_t lastDotPosition = filePath.rfind(".");
59 bool positionFlag = (lastDotPosition == std::string::npos) || (lastDotPosition == filePath.size() - 1);
60 if (positionFlag) {
61 return "";
62 }
63 return filePath.substr(lastDotPosition + 1);
64 }
65
ValidFileType(const std::string & filePath,const std::initializer_list<std::string> types)66 bool FileUtils::ValidFileType(const std::string& filePath, const std::initializer_list<std::string> types)
67 {
68 std::string suffix = GetSuffix(filePath);
69 bool flag = suffix.empty() || (StringUtils::ContainsCase(types, suffix) == false);
70 if (flag) {
71 PrintErrorNumberMsg("NOT_SUPPORT_ERROR", NOT_SUPPORT_ERROR, "Not support file: " + filePath);
72 return false;
73 }
74 return true;
75 }
76
Write(const std::string & content,const std::string & output)77 int FileUtils::Write(const std::string& content, const std::string& output)
78 {
79 std::ofstream outFile(output, std::ios::binary);
80 bool flag = (outFile.rdstate() != 0);
81 if (flag) {
82 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open output file: " + output + " failed");
83 return IO_ERROR;
84 }
85 outFile.write(&content[0], content.size());
86 if (outFile.rdstate() != 0) {
87 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "Failed to write data to output stream.");
88 return IO_ERROR;
89 }
90 return RET_OK;
91 }
92
Read(std::ifstream & input,std::string & ret)93 int FileUtils::Read(std::ifstream& input, std::string& ret)
94 {
95 ret.clear();
96 if (input.rdstate() != 0) {
97 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "invalid input stream");
98 return IO_ERROR;
99 }
100 ret.clear();
101 std::string buffer(FileUtils::FILE_BUFFER_BLOCK, 0);
102 while (input) {
103 input.read(&buffer[0], buffer.size());
104 if (input.fail() && !input.eof()) {
105 SIGNATURE_TOOLS_LOGE("error occurred while reading data");
106 return IO_ERROR;
107 }
108 ret.append(&buffer[0], input.gcount());
109 }
110 return RET_OK;
111 }
112
ReadFile(const std::string & path,std::string & ret)113 int FileUtils::ReadFile(const std::string& path, std::string& ret)
114 {
115 std::ifstream file(path, std::ios::binary);
116 bool flag = (file.rdstate() != 0);
117 if (flag) {
118 PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open input file: " + path + " failed");
119 return IO_ERROR;
120 }
121 if (Read(file, ret) < 0) {
122 SIGNATURE_TOOLS_LOGE("read error!");
123 return IO_ERROR;
124 }
125 return RET_OK;
126 }
127
ReadFileByOffsetAndLength(std::ifstream & file,size_t offset,size_t length,std::string & ret)128 int FileUtils::ReadFileByOffsetAndLength(std::ifstream& file, size_t offset, size_t length, std::string& ret)
129 {
130 if (length > INT_MAX) {
131 SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length);
132 return RET_FAILED;
133 }
134 if (ReadInputByOffsetAndLength(file, offset, length, ret) < 0) {
135 SIGNATURE_TOOLS_LOGE("Error readInputByOffsetAndLength");
136 return IO_ERROR;
137 }
138 return RET_OK;
139 }
140
ReadInputByOffsetAndLength(std::ifstream & input,size_t offset,size_t length,std::string & ret)141 int FileUtils::ReadInputByOffsetAndLength(std::ifstream& input, 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 -1;
146 }
147 input.seekg(offset);
148 if (ReadInputByLength(input, length, ret) < 0) {
149 SIGNATURE_TOOLS_LOGE("Error readInputByLength");
150 return -1;
151 }
152 return RET_OK;
153 }
154
ReadInputByLength(std::ifstream & input,size_t length,std::string & ret)155 int FileUtils::ReadInputByLength(std::ifstream& input, size_t length, std::string& ret)
156 {
157 if (length > INT_MAX) {
158 SIGNATURE_TOOLS_LOGE("Size cannot be greater than Integer max value: %zu", length);
159 return -1;
160 }
161 if (input.rdstate() != 0) {
162 SIGNATURE_TOOLS_LOGE("Error input");
163 return -1;
164 }
165 ret.clear();
166
167 char* buffer = new (std::nothrow)char[FILE_BUFFER_BLOCK];
168 if (buffer == NULL) {
169 SIGNATURE_TOOLS_LOGE("create buffer error!");
170 return -1;
171 }
172 size_t hasReadLen = 0;
173
174 while (hasReadLen < length && input) {
175 int readLen = static_cast<int>(std::min(length - hasReadLen, (size_t)FILE_BUFFER_BLOCK));
176 input.read(buffer, readLen);
177 bool flag = (input.gcount() != readLen);
178 if (flag) {
179 delete[] buffer;
180 SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length);
181 return -1;
182 }
183 ret.append(buffer, readLen);
184 hasReadLen += readLen;
185 }
186 delete[] buffer;
187 if (hasReadLen != length) {
188 SIGNATURE_TOOLS_LOGE("read %zu bytes data less than %zu", hasReadLen, length);
189 return -1;
190 }
191 return RET_OK;
192 }
193
AppendWriteFileByOffsetToFile(std::ifstream & input,std::ofstream & out,size_t offset,size_t size)194 bool FileUtils::AppendWriteFileByOffsetToFile(std::ifstream& input, std::ofstream& out, size_t offset, size_t size)
195 {
196 if (input.rdstate() != 0) {
197 SIGNATURE_TOOLS_LOGE("input failed.");
198 return false;
199 }
200 if (out.rdstate() != 0) {
201 SIGNATURE_TOOLS_LOGE("Failed get out stream");
202 return false;
203 }
204 input.seekg(offset);
205 if (WriteInputToOutPut(input, out, size) < 0) {
206 SIGNATURE_TOOLS_LOGE("Error: writeInputToOutPut");
207 return false;
208 }
209 return true;
210 }
211
AppendWriteFileToFile(const std::string & inputFile,const std::string & outputFile)212 bool FileUtils::AppendWriteFileToFile(const std::string& inputFile, const std::string& outputFile)
213 {
214 std::ifstream input(inputFile, std::ios::binary);
215 std::ofstream output(outputFile, std::ios::binary | std::ios::app);
216 bool flag = (0 != input.rdstate());
217 if (flag) {
218 SIGNATURE_TOOLS_LOGE("Failed to get input stream object!");
219 return false;
220 }
221 flag = (0 != output.rdstate());
222 if (flag) {
223 SIGNATURE_TOOLS_LOGE("Failed to get output stream object!");
224 return false;
225 }
226 char* buffer = new char[FILE_BUFFER_BLOCK];
227 while (!input.eof()) {
228 input.read(buffer, FILE_BUFFER_BLOCK);
229
230 if (input.fail() && !input.eof()) {
231 SIGNATURE_TOOLS_LOGE("error occurred while reading data");
232 delete[]buffer;
233 return false;
234 }
235 std::streamsize readLen = input.gcount();
236 if (readLen > 0) {
237 output.write(buffer, readLen);
238 }
239 if (!output) {
240 SIGNATURE_TOOLS_LOGE("error occurred while writing data");
241 delete[]buffer;
242 return false;
243 }
244 }
245 delete[]buffer;
246 return true;
247 }
248
AppendWriteByteToFile(const std::string & bytes,const std::string & outputFile)249 bool FileUtils::AppendWriteByteToFile(const std::string& bytes, const std::string& outputFile)
250 {
251 std::ofstream output(outputFile, std::ios::binary | std::ios::app);
252 bool flag = (WriteByteToOutFile(bytes, output) == false);
253 if (flag) {
254 SIGNATURE_TOOLS_LOGE("Failed to write data to output stream, outfile: %s", outputFile.c_str());
255 return false;
256 }
257 return true;
258 }
259
WriteInputToOutPut(std::ifstream & input,std::ofstream & output,size_t length)260 int FileUtils::WriteInputToOutPut(std::ifstream& input, std::ofstream& output, size_t length)
261 {
262 int result = RET_OK;
263 char* buf = new (std::nothrow)char[FILE_BUFFER_BLOCK];
264 if (buf == NULL) {
265 SIGNATURE_TOOLS_LOGE("create buffer error!");
266 return RET_FAILED;
267 }
268
269 while (input) {
270 int min = std::min(static_cast<int>(length), FILE_BUFFER_BLOCK);
271 input.read(buf, min);
272 if (input.fail() && !input.eof()) {
273 SIGNATURE_TOOLS_LOGE("read error!");
274 delete[] buf;
275 return IO_ERROR;
276 }
277 length -= input.gcount();
278 output.write(buf, input.gcount());
279 if (!output.good()) {
280 SIGNATURE_TOOLS_LOGE("write error!");
281 delete[] buf;
282 return IO_ERROR;
283 }
284
285 if (length <= 0) {
286 break;
287 }
288 }
289 delete[] buf;
290 // After the file is written, datasize must be 0, so the if condition will never hold
291 if (length != 0) {
292 SIGNATURE_TOOLS_LOGE("written length error!");
293 return IO_ERROR;
294 }
295 return result;
296 }
297
WriteInputToOutPut(const std::string & input,const std::string & output)298 bool FileUtils::WriteInputToOutPut(const std::string& input, const std::string& output)
299 {
300 std::ifstream in(input, std::ios::binary);
301 std::ofstream out(output, std::ios::binary);
302 bool flag = (in.rdstate() != 0);
303 if (flag) {
304 SIGNATURE_TOOLS_LOGE("Failed to get input stream object!");
305 return false;
306 }
307 flag = (out.rdstate() != 0);
308 if (flag) {
309 SIGNATURE_TOOLS_LOGE("Failed to get output stream object!");
310 return false;
311 }
312 char* buffer = new char[FILE_BUFFER_BLOCK];
313 while (!in.eof()) {
314 in.read(buffer, FILE_BUFFER_BLOCK);
315
316 if (in.fail() && !in.eof()) {
317 SIGNATURE_TOOLS_LOGE("error occurred while reading data");
318 delete[]buffer;
319 return false;
320 }
321
322 std::streamsize readLen = in.gcount();
323 if (readLen > 0) {
324 out.write(buffer, readLen);
325 }
326
327 if (!out) {
328 SIGNATURE_TOOLS_LOGE("error occurred while writing data");
329 delete[]buffer;
330 return false;
331 }
332 }
333 delete[]buffer;
334 return true;
335 }
336
WriteByteToOutFile(const std::string & bytes,const std::string & outFile)337 bool FileUtils::WriteByteToOutFile(const std::string& bytes, const std::string& outFile)
338 {
339 std::ofstream ops(outFile, std::ios::binary);
340 bool flag = (WriteByteToOutFile(bytes, ops) == false);
341 if (flag) {
342 SIGNATURE_TOOLS_LOGE("Failed to write data to ops, outfile: %s", outFile.c_str());
343 return false;
344 }
345 return true;
346 }
347
WriteByteToOutFile(const std::string & bytes,std::ofstream & outFile)348 bool FileUtils::WriteByteToOutFile(const std::string& bytes, std::ofstream& outFile)
349 {
350 if (outFile.rdstate() != 0) {
351 SIGNATURE_TOOLS_LOGE("Failed to get output stream object, outfile");
352 return false;
353 }
354 outFile.write(&bytes[0], bytes.size());
355 if (outFile.rdstate() != 0) {
356 SIGNATURE_TOOLS_LOGE("Failed to write data to ops, outfile ");
357 return false;
358 }
359 outFile.flush();
360 if (outFile.rdstate() != 0) {
361 SIGNATURE_TOOLS_LOGE("Flush error");
362 return false;
363 }
364 return true;
365 }
366
WriteByteToOutFile(const std::vector<int8_t> & bytes,std::ofstream & outFile)367 bool FileUtils::WriteByteToOutFile(const std::vector<int8_t>& bytes, std::ofstream& outFile)
368 {
369 if (outFile.rdstate() != 0) {
370 SIGNATURE_TOOLS_LOGE("Failed to get output stream object, outfile");
371 return false;
372 }
373 outFile.write((char*)&bytes[0], bytes.size());
374 if (outFile.rdstate() != 0) {
375 SIGNATURE_TOOLS_LOGE("Failed to write data to ops, outfile ");
376 return false;
377 }
378 outFile.flush();
379 if (outFile.rdstate() != 0) {
380 SIGNATURE_TOOLS_LOGE("Flush error");
381 return false;
382 }
383 return true;
384 }
385
IsRunnableFile(const std::string & name)386 bool FileUtils::IsRunnableFile(const std::string& name)
387 {
388 if (name.empty()) {
389 return false;
390 }
391 size_t dotPos = name.rfind('.');
392 if (dotPos == std::string::npos) {
393 return false;
394 }
395 std::string suffix = name.substr(dotPos + 1);
396 if (suffix == "an" || suffix == "abc") {
397 return true;
398 }
399 std::string libDir = name.substr(0, LIBS_PATH_PREFIX.size());
400 if (LIBS_PATH_PREFIX.compare(libDir) == 0) {
401 return true;
402 }
403 return false;
404 }
405
IsValidFile(std::string file)406 bool FileUtils::IsValidFile(std::string file)
407 {
408 std::filesystem::path filePath = file;
409 bool flag = std::filesystem::exists(filePath);
410 if (!flag) {
411 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + file + "' file is not exists");
412 return false;
413 }
414 flag = std::filesystem::is_directory(filePath);
415 if (flag) {
416 PrintErrorNumberMsg("FILE_NOT_FOUND", FILE_NOT_FOUND, "'" + file + "' file is a directory not file");
417 return false;
418 }
419 return true;
420 }
421
GetFileLen(const std::string & file)422 int64_t FileUtils::GetFileLen(const std::string& file)
423 {
424 std::filesystem::path filePath = file;
425 bool flag = std::filesystem::exists(filePath) && std::filesystem::is_regular_file(filePath);
426 if (flag) {
427 return std::filesystem::file_size(filePath);
428 }
429 return -1;
430 }
431
DelDir(const std::string & file)432 void FileUtils::DelDir(const std::string& file)
433 {
434 std::filesystem::path filePath = file;
435 bool flag = std::filesystem::is_directory(filePath);
436 if (flag) {
437 for (auto& p : std::filesystem::recursive_directory_iterator(filePath)) {
438 DelDir(p.path());
439 }
440 }
441 std::filesystem::remove(file);
442 return;
443 }
444
445 } // namespace SignatureTools
446 } // namespace OHOS