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