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 "file_util.h"
17 #include <algorithm>
18 #include <cstdio>
19 #include <cstring>
20 #ifdef __gnu_linux__
21 #include <experimental/filesystem>
22 #else
23 #include <filesystem>
24 #endif
25 #include <fstream>
26 #include <iostream>
27 #include <iterator>
28 namespace OHOS {
29 namespace HiviewDFX {
30 namespace FileUtil {
31 using namespace std;
32 #ifdef __gnu_linux__
33 namespace fs = experimental::filesystem;
34 #else
35 namespace fs = std::filesystem;
36 constexpr int PATH_MAX = 4096;
37 #endif
38 constexpr int MODE_MAX = 07777;
39 constexpr int MAX_FILE_LENGTH = 32 * 1024 * 1024; // 32MB
LoadStringFromFile(const string & filePath,string & content)40 bool LoadStringFromFile(const string& filePath, string& content)
41 {
42 ifstream file(filePath.c_str());
43 if (!file.is_open()) {
44 return false;
45 }
46
47 file.seekg(0, ios::end);
48 const long fileLength = static_cast<long>(file.tellg());
49 if (fileLength > MAX_FILE_LENGTH) {
50 return false;
51 }
52
53 content.clear();
54 file.seekg(0, ios::beg);
55 copy(istreambuf_iterator<char>(file), istreambuf_iterator<char>(), back_inserter(content));
56 return true;
57 }
58
LoadBufferFromNodeFile(const string & filePath,vector<char> & content)59 bool LoadBufferFromNodeFile(const string& filePath, vector<char>& content)
60 {
61 string realPath;
62 if (!PathToRealPath(filePath, realPath)) {
63 return false;
64 }
65
66 FILE* fp = fopen(realPath.c_str(), "r");
67 if (fp == nullptr) {
68 return false;
69 }
70
71 char ch = fgetc(fp);
72 int byteCount = 1;
73 while (!feof(fp)) {
74 if (byteCount > MAX_FILE_LENGTH) {
75 fclose(fp);
76 fp = nullptr;
77 content.clear();
78 return false;
79 }
80
81 content.push_back(ch);
82 ch = fgetc(fp);
83 byteCount++;
84 }
85
86 fclose(fp);
87 fp = nullptr;
88 return true;
89 }
90
LoadBufferFromFile(const std::string & filePath,std::vector<char> & content)91 bool LoadBufferFromFile(const std::string& filePath, std::vector<char>& content)
92 {
93 ifstream file;
94 file.open(filePath.c_str(), ios::in | ios::binary);
95 if (!file.is_open()) {
96 return false;
97 }
98
99 file.seekg(0, std::ios::end);
100 const long fileLength = static_cast<long>(file.tellg());
101 if (fileLength > MAX_FILE_LENGTH) {
102 return false;
103 }
104
105 // lseek is not support the linux file node
106 if (fileLength < 0) {
107 return LoadBufferFromNodeFile(filePath, content);
108 }
109
110 if (fileLength == 0) {
111 content.clear();
112 return true;
113 }
114
115 file.seekg(0, std::ios::beg);
116 if (file.fail()) {
117 return false;
118 }
119
120 content.resize(fileLength);
121 file.read(&content[0], fileLength);
122 return true;
123 }
124
SaveStringToFile(const std::string & filePath,const std::string & content,bool truncated)125 bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated)
126 {
127 if (content.empty()) {
128 return true;
129 }
130
131 ofstream file;
132 if (truncated) {
133 file.open(filePath.c_str(), ios::out | ios::trunc);
134 } else {
135 file.open(filePath.c_str(), ios::out | ios::app);
136 }
137
138 if (!file.is_open()) {
139 return false;
140 }
141
142 file.write(content.c_str(), content.length());
143 if (file.fail()) {
144 return false;
145 }
146
147 return true;
148 }
149
SaveBufferToFile(const string & filePath,const vector<char> & content,bool truncated)150 bool SaveBufferToFile(const string& filePath, const vector<char>& content, bool truncated)
151 {
152 // if the file is not exist,create it first!
153
154 ios_base::openmode mode = truncated ? (ios::out | ios::binary | ios::trunc) : (ios::out | ios::binary | ios::app);
155 ofstream file;
156 file.open(filePath.c_str(), mode);
157 if (!file.is_open()) {
158 return false;
159 }
160
161 if (content.empty()) {
162 return true;
163 }
164
165 file.write(&content[0], content.size());
166 return true;
167 }
168
FileExists(const std::string & fileName)169 bool FileExists(const std::string& fileName)
170 {
171 error_code ec;
172 bool ret = fs::exists(fileName, ec); // noexcept
173 if (ec) {
174 printf("%s\n", ec.message().c_str());
175 }
176 return ret;
177 }
178
ExtractFilePath(const std::string & fileFullName)179 std::string ExtractFilePath(const std::string& fileFullName)
180 {
181 return fs::path(fileFullName).parent_path().string();
182 }
183
ExtractFileName(const std::string & fileFullName)184 std::string ExtractFileName(const std::string& fileFullName)
185 {
186 return fs::path(fileFullName).filename().string();
187 }
188
GetDirFiles(const std::string & path,std::vector<std::string> & files)189 void GetDirFiles(const std::string& path, std::vector<std::string>& files)
190 {
191 files.clear();
192 for (const auto& p : fs::directory_iterator(path)) {
193 files.push_back(p.path().string());
194 }
195 return;
196 }
197
198
ForceCreateDirectory(const std::string & path)199 bool ForceCreateDirectory(const std::string& path)
200 {
201 error_code ec;
202 if (fs::exists(path, ec)) {
203 return true;
204 }
205 if (!fs::create_directories(path, ec)) {
206 return false;
207 }
208 return fs::exists(path, ec);
209 }
210
ForceCreateDirectory(const std::string & path,int mode)211 bool ForceCreateDirectory(const std::string& path, int mode)
212 {
213 if (!ForceCreateDirectory(path)) {
214 return false;
215 }
216 return ChangeModeDirectory(path, mode);
217 }
218
ForceRemoveDirectory(const std::string & path,bool isNeedDeleteGivenDirSelf)219 bool ForceRemoveDirectory(const std::string& path, bool isNeedDeleteGivenDirSelf)
220 {
221 error_code ec;
222 fs::remove_all(path, ec);
223 return true;
224 }
225
226 /* return true if file removed successfully, return false if file not exist. */
RemoveFile(const std::string & fileName)227 bool RemoveFile(const std::string& fileName)
228 {
229 error_code ec;
230 return fs::remove(fileName, ec);
231 }
232
GetFileSize(const std::string & path)233 uint64_t GetFileSize(const std::string& path)
234 {
235 error_code ec;
236 return fs::file_size(path, ec);
237 }
238
GetFolderSize(const std::string & path)239 uint64_t GetFolderSize(const std::string& path)
240 {
241 vector<string> files;
242 struct stat statbuf = {0};
243 GetDirFiles(path, files);
244 uint64_t totalSize = 0;
245 for (auto& file : files) {
246 if (stat(file.c_str(), &statbuf) == 0) {
247 totalSize += statbuf.st_size;
248 }
249 }
250
251 return totalSize;
252 }
253
CreateFile(const std::string & path,mode_t mode)254 int CreateFile(const std::string &path, mode_t mode)
255 {
256 if (FileExists(path)) {
257 return 0;
258 } else {
259 std::ofstream fout(path);
260 if (!fout.is_open()) {
261 return -1;
262 }
263 fout.flush();
264 fout.close();
265 if (ChangeMode(path, mode) != 0) {
266 return -1;
267 }
268 }
269 return 0;
270 }
271
CopyFile(const std::string & src,const std::string & des)272 int CopyFile(const std::string &src, const std::string &des)
273 {
274 std::ifstream fin(src);
275 std::ofstream fout(des);
276 if (!fin.is_open()) {
277 return -1;
278 }
279 if (!fout.is_open()) {
280 return -1;
281 }
282 fout << fin.rdbuf();
283 if (fout.fail()) {
284 fout.clear();
285 }
286 fout.flush();
287 return 0;
288 }
289
IsDirectory(const std::string & path)290 bool IsDirectory(const std::string &path)
291 {
292 return fs::is_directory(path);
293 }
294
GetLastLine(std::istream & fin,std::string & line,uint32_t maxLen)295 bool GetLastLine(std::istream &fin, std::string &line, uint32_t maxLen)
296 {
297 if (fin.tellg() <= 0) {
298 return false;
299 } else {
300 fin.seekg(-1, fin.cur);
301 }
302 uint32_t count = 0;
303 while (fin.good() && fin.peek() == fin.widen('\n') && fin.tellg() > 0 && count < maxLen) {
304 fin.seekg(-1, fin.cur);
305 count++;
306 }
307 if (!fin.good() || count >= maxLen) {
308 return false;
309 }
310 if (fin.tellg() == 0) {
311 return true;
312 }
313 count = 0;
314 while (fin.good() && fin.peek() != fin.widen('\n') && fin.tellg() > 0 && count < maxLen) {
315 fin.seekg(-1, fin.cur);
316 count++;
317 }
318 if (!fin.good() || count >= maxLen) {
319 return false;
320 }
321 if (fin.tellg() != 0) {
322 fin.seekg(1, fin.cur);
323 }
324 auto oldPos = fin.tellg();
325 getline(fin, line);
326 fin.seekg(oldPos);
327 return true;
328 }
329
GetParentDir(const std::string & path)330 std::string GetParentDir(const std::string &path)
331 {
332 string str = ExtractFilePath(path);
333 if (str.empty()) {
334 return "";
335 }
336 return str.substr(0, str.size() - 1);
337 }
338
339 // inner function, and param is legitimate
ChangeMode(const string & fileName,const mode_t & mode)340 bool ChangeMode(const string& fileName, const mode_t& mode)
341 {
342 if (!FileExists(fileName)) {
343 return false;
344 }
345 if (mode > MODE_MAX) {
346 return false;
347 }
348 auto perm = static_cast<fs::perms>(mode);
349 fs::permissions(fileName, perm);
350 return true;
351 }
352
ChangeModeDirectory(const string & path,const mode_t & mode)353 bool ChangeModeDirectory(const string& path, const mode_t& mode)
354 {
355 if (!FileExists(path)) {
356 return false;
357 }
358
359 for (auto& p : fs::recursive_directory_iterator(path)) {
360 string tmpPath = p.path().string();
361 replace(tmpPath.begin(), tmpPath.end(), '\\', '/');
362 if (!ChangeMode(tmpPath, mode)) {
363 return false;
364 }
365 }
366 return ChangeMode(path, mode);
367 }
368
PathToRealPath(const std::string & path,std::string & realPath)369 bool PathToRealPath(const std::string& path, std::string& realPath)
370 {
371 if (path.empty()) {
372 return false;
373 }
374
375 if ((path.length() >= PATH_MAX)) {
376 return false;
377 }
378 if (!fs::exists(path)) {
379 return false;
380 }
381 fs::path absolutePath = fs::canonical(path);
382
383 realPath = absolutePath.string();
384 #ifdef _WIN32
385 FormatPath2UnixStyle(realPath);
386 #endif
387 return true;
388 }
389 }
390 }
391 }
392