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_ex.h"
17 #include <fstream>
18 #include <iostream>
19 #include <algorithm>
20 #include <iterator>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <cstdio>
25 #include <securec.h>
26 #include <cstring>
27 #include "directory_ex.h"
28 #include "utils_log.h"
29
30 using namespace std;
31
32 const int MAX_FILE_LENGTH = 32 * 1024 * 1024;
33
34 namespace OHOS {
35 #ifdef UTILS_CXX_RUST
RustLoadStringFromFile(const rust::String & filePath,rust::String & content)36 bool RustLoadStringFromFile(const rust::String& filePath, rust::String& content)
37 {
38 std::string tmpPath(filePath);
39 std::string tmpContent(content);
40 if (LoadStringFromFile(tmpPath, tmpContent)) {
41 content = tmpContent;
42 return true;
43 }
44 return false;
45 }
46
RustLoadStringFromFd(int fd,rust::String & content)47 bool RustLoadStringFromFd(int fd, rust::String& content)
48 {
49 std::string tmpContent(content);
50 if (LoadStringFromFd(fd, tmpContent)) {
51 content = tmpContent;
52 return true;
53 }
54 return false;
55 }
56
RustLoadBufferFromFile(const rust::String & filePath,rust::vec<char> & content)57 bool RustLoadBufferFromFile(const rust::String& filePath, rust::vec<char>& content)
58 {
59 std::string tmpPath(filePath);
60 std::vector<char> tmpContent(content.begin(), content.end());
61 if (LoadBufferFromFile(tmpPath, tmpContent)) {
62 std::copy(tmpContent.begin(), tmpContent.end(), std::back_inserter(content));
63 return true;
64 }
65 return false;
66 }
67
RustSaveBufferToFile(const rust::String & filePath,const rust::vec<char> & content,bool truncated)68 bool RustSaveBufferToFile(const rust::String& filePath, const rust::vec<char>& content, bool truncated)
69 {
70 std::string tmpPath(filePath);
71 std::vector<char> tmpContent(content.begin(), content.end());
72 return SaveBufferToFile(tmpPath, tmpContent, truncated);
73 }
74
RustSaveStringToFile(const rust::String & filePath,const rust::String & content,bool truncated)75 bool RustSaveStringToFile(const rust::String& filePath, const rust::String& content, bool truncated)
76 {
77 std::string tmpPath(filePath);
78 std::string tmpContent(content);
79 return SaveStringToFile(tmpPath, tmpContent, truncated);
80 }
81
RustSaveStringToFd(int fd,const rust::String & content)82 bool RustSaveStringToFd(int fd, const rust::String& content)
83 {
84 std::string tmpContent(content);
85 return SaveStringToFd(fd, tmpContent);
86 }
87
RustFileExists(const rust::String & fileName)88 bool RustFileExists(const rust::String& fileName)
89 {
90 std::string tmpName(fileName);
91 return FileExists(tmpName);
92 }
93
RustStringExistsInFile(const rust::String & fileName,const rust::String & subStr,bool caseSensitive)94 bool RustStringExistsInFile(const rust::String& fileName, const rust::String& subStr, bool caseSensitive)
95 {
96 std::string tmpName(fileName);
97 std::string tmpStr(subStr);
98 return StringExistsInFile(tmpName, tmpStr, caseSensitive);
99 }
100
RustCountStrInFile(const rust::String & fileName,const rust::String & subStr,bool caseSensitive)101 int RustCountStrInFile(const rust::String& fileName, const rust::String& subStr, bool caseSensitive)
102 {
103 std::string tmpName(fileName);
104 std::string tmpStr(subStr);
105 return CountStrInFile(tmpName, tmpStr, caseSensitive);
106 }
107
108 #endif
109
LoadStringFromFile(const string & filePath,string & content)110 bool LoadStringFromFile(const string& filePath, string& content)
111 {
112 ifstream file(filePath.c_str());
113 if (!file.is_open()) {
114 UTILS_LOGD("open file failed! filePath:%{public}s", filePath.c_str());
115 return false;
116 }
117
118 file.seekg(0, ios::end);
119 const long long fileLength = file.tellg();
120 if (fileLength > MAX_FILE_LENGTH) {
121 UTILS_LOGD("invalid file length(%{public}lld)!", fileLength);
122 return false;
123 }
124
125 content.clear();
126 file.seekg(0, ios::beg);
127 copy(istreambuf_iterator<char>(file), istreambuf_iterator<char>(), back_inserter(content));
128 return true;
129 }
130
GetFileNameByFd(const int fd)131 string GetFileNameByFd(const int fd)
132 {
133 if (fd <= 0) {
134 return string();
135 }
136
137 string fdPath = "/proc/self/fd/" + std::to_string(fd);
138 char fileName[PATH_MAX + 1] = {0};
139
140 ssize_t ret = readlink(fdPath.c_str(), fileName, PATH_MAX);
141 if (ret < 0 || ret > PATH_MAX) {
142 UTILS_LOGD("Get fileName failed, ret is: %{public}d!", ret);
143 return string();
144 }
145 fileName[ret] = '\0';
146 return string(fileName);
147 }
148
LoadStringFromFdToFile(int fd,string & content)149 bool LoadStringFromFdToFile(int fd, string& content)
150 {
151 string fileName = GetFileNameByFd(fd);
152 if (fileName.empty()) {
153 UTILS_LOGD("LoadStringFromFd get file name by fd failed!");
154 return false;
155 }
156
157 if (!LoadStringFromFile(fileName, content)) {
158 UTILS_LOGE("LoadStringFromFd get string from file failed!");
159 return false;
160 }
161 return true;
162 }
163
LoadStringFromFd(int fd,string & content)164 bool LoadStringFromFd(int fd, string& content)
165 {
166 if (fd <= 0) {
167 UTILS_LOGD("invalid fd:%{public}d", fd);
168 return false;
169 }
170
171 const off_t fileLength = lseek(fd, 0, SEEK_END);
172 if (fileLength > MAX_FILE_LENGTH) {
173 UTILS_LOGE("invalid file length(%{public}jd)!", static_cast<intmax_t>(fileLength));
174 return false;
175 }
176
177 // lseek is not support the linux file node
178 if (fileLength < 0) {
179 return LoadStringFromFdToFile(fd, content);
180 }
181
182 if (fileLength == 0) {
183 return true;
184 }
185
186 content.resize(fileLength);
187 off_t loc = lseek(fd, 0, SEEK_SET);
188 if (loc == -1) {
189 UTILS_LOGE("lseek file to begin failed!");
190 return false;
191 }
192
193 const ssize_t len = read(fd, content.data(), fileLength);
194 if (len != fileLength) {
195 UTILS_LOGE("the length read from file is not equal to fileLength!len:%{public}zd,fileLen:%{public}jd",
196 len, static_cast<intmax_t>(fileLength));
197 return false;
198 }
199
200 return true;
201 }
202
SaveStringToFile(const std::string & filePath,const std::string & content,bool truncated)203 bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated /*= true*/)
204 {
205 if (content.empty()) {
206 UTILS_LOGI("content is empty, no need to save!");
207 return true;
208 }
209
210 ofstream file;
211 if (truncated) {
212 file.open(filePath.c_str(), ios::out | ios::trunc);
213 } else {
214 file.open(filePath.c_str(), ios::out | ios::app);
215 }
216
217 if (!file.is_open()) {
218 UTILS_LOGD("open file failed! filePath:%{private}s", filePath.c_str());
219 return false;
220 }
221
222 file.write(content.c_str(), content.length());
223 if (file.fail()) {
224 UTILS_LOGE("write content to file failed!file:%{private}s, content:%{private}s",
225 filePath.c_str(), content.c_str());
226 return false;
227 }
228 return true;
229 }
230
SaveStringToFd(int fd,const std::string & content)231 bool SaveStringToFd(int fd, const std::string& content)
232 {
233 if (fd <= 0) {
234 UTILS_LOGD("invalid fd:%{public}d", fd);
235 return false;
236 }
237
238 if (content.empty()) {
239 UTILS_LOGI("content is empty, no need to save!");
240 return true;
241 }
242
243 const ssize_t len = write(fd, content.c_str(), content.length());
244 if (len < 0) {
245 UTILS_LOGE("write file failed!errno:%{public}d, err:%{public}s", errno, strerror(errno));
246 return false;
247 }
248
249 if (static_cast<unsigned long>(len) != content.length()) {
250 UTILS_LOGE("the length write to file is not equal to fileLength!len:%{public}zd, fileLen:%{public}zu",
251 len, content.length());
252 return false;
253 }
254
255 return true;
256 }
257
LoadBufferFromNodeFile(const string & filePath,vector<char> & content)258 bool LoadBufferFromNodeFile(const string& filePath, vector<char>& content)
259 {
260 string realPath;
261 if (!PathToRealPath(filePath, realPath)) {
262 UTILS_LOGD("filePath to realPath failed! filePath:%{private}s", filePath.c_str());
263 return false;
264 }
265
266 FILE *fp = fopen(realPath.c_str(), "r");
267 if (fp == nullptr) {
268 UTILS_LOGD("open file failed! filePath:%{private}s", realPath.c_str());
269 return false;
270 }
271
272 char ch = fgetc(fp);
273 int byteCount = 1;
274 while (!feof(fp)) {
275 if (byteCount > MAX_FILE_LENGTH) {
276 UTILS_LOGE("LoadBufferFromNodeFile invalid file length(%{public}d)!", byteCount);
277 fclose(fp);
278 fp = nullptr;
279 content.clear();
280 return false;
281 }
282
283 content.push_back(ch);
284 ch = fgetc(fp);
285 byteCount++;
286 }
287
288 fclose(fp);
289 fp = nullptr;
290 return true;
291 }
292
293 /* load file to buffer. If the buffer is not empty,then overwrite */
LoadBufferFromFile(const string & filePath,vector<char> & content)294 bool LoadBufferFromFile(const string& filePath, vector<char>& content)
295 {
296 ifstream file;
297 file.open(filePath.c_str(), ios::in | ios::binary);
298 if (!file.is_open()) {
299 UTILS_LOGD("open file failed! filePath:%{private}s", filePath.c_str());
300 return false;
301 }
302
303 file.seekg(0, std::ios::end);
304 const long long fileLength = file.tellg();
305 if (fileLength > MAX_FILE_LENGTH) {
306 UTILS_LOGD("invalid file length(%{public}lld)!", fileLength);
307 return false;
308 }
309
310 // lseek is not support the linux file node
311 if (fileLength < 0) {
312 return LoadBufferFromNodeFile(filePath, content);
313 }
314
315 if (fileLength == 0) {
316 content.clear();
317 return true;
318 }
319
320 file.seekg(0, std::ios::beg);
321 if (file.fail()) {
322 UTILS_LOGE("seekg file to begin failed!filePath:%{private}s", filePath.c_str());
323 return false;
324 }
325
326 content.resize(fileLength);
327 file.read(&content[0], fileLength);
328 return true;
329 }
330
SaveBufferToFile(const string & filePath,const vector<char> & content,bool truncated)331 bool SaveBufferToFile(const string& filePath, const vector<char>& content, bool truncated /*= true*/)
332 {
333 if (content.empty()) {
334 UTILS_LOGI("content is empty, no need to save!");
335 return true;
336 }
337
338 // if the file is not exist,create it first!
339 uint32_t mode = truncated ? (ios::out | ios::binary | ios::trunc) : (ios::out | ios::binary | ios::app);
340 ofstream file;
341 file.open(filePath.c_str(), mode);
342 if (!file.is_open()) {
343 UTILS_LOGD("open file failed! filePath:%{private}s, mode:%{private}d", filePath.c_str(), mode);
344 return false;
345 }
346
347 file.write(&content[0], content.size());
348 return true;
349 }
350
FileExists(const string & fileName)351 bool FileExists(const string& fileName)
352 {
353 return (access(fileName.c_str(), F_OK) == 0);
354 }
355
StringExistsInFile(const string & fileName,const string & subStr,bool caseSensitive)356 bool StringExistsInFile(const string& fileName, const string& subStr, bool caseSensitive /*= true*/)
357 {
358 if (subStr.empty()) {
359 UTILS_LOGD("String is empty");
360 return false;
361 }
362
363 string str;
364 if (!LoadStringFromFile(fileName, str)) {
365 UTILS_LOGD("File load fail, filePath:%{private}s", fileName.c_str());
366 return false;
367 }
368
369 if (caseSensitive) {
370 return (str.find(subStr) != string::npos);
371 }
372
373 string strlower(str);
374 string sublower(subStr);
375 transform(str.begin(), str.end(), strlower.begin(), ::tolower);
376 transform(subStr.begin(), subStr.end(), sublower.begin(), ::tolower);
377 return (strlower.find(sublower) != string::npos);
378 }
379
CountStrInStr(const string & str,const string & subStr)380 int CountStrInStr(const string& str, const string& subStr)
381 {
382 if (subStr.empty()) {
383 UTILS_LOGD("subStr is empty");
384 return 0;
385 }
386
387 size_t position = 0;
388 int count = 0;
389 size_t length = subStr.length();
390 while ((position = str.find(subStr, position)) != string::npos) {
391 position += length;
392 count++;
393 }
394
395 return count;
396 }
397
CountStrInFile(const string & fileName,const string & subStr,bool caseSensitive)398 int CountStrInFile(const string& fileName, const string& subStr, bool caseSensitive /*= true*/)
399 {
400 if (subStr.empty()) {
401 UTILS_LOGD("String is empty");
402 return -1;
403 }
404
405 string str;
406 if (!LoadStringFromFile(fileName, str)) {
407 UTILS_LOGD("File load fail, filePath:%{private}s", fileName.c_str());
408 return -1;
409 }
410
411 // If case-insensitive, strings are converted to lowercase.
412 if (caseSensitive) {
413 return CountStrInStr(str, subStr);
414 }
415
416 string strlower(str);
417 string sublower(subStr);
418 transform(str.begin(), str.end(), strlower.begin(), ::tolower);
419 transform(subStr.begin(), subStr.end(), sublower.begin(), ::tolower);
420 return CountStrInStr(strlower, sublower);
421 }
422 }
423