• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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