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