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