1 /*
2 * Copyright (c) 2024 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 "util/file.h"
17
18 #include <climits>
19 #include <cstdlib>
20 #include <cstring>
21 #include <dirent.h>
22 #include <functional>
23 #include <string>
24 #include <algorithm>
25 #include <queue>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include "util/common.h"
31 #include "util/logger.h"
32 #include "util/string_helper.h"
33 #include "util/string_builder.h"
34
35 namespace OHOS {
36 namespace Idl {
File(const std::string & path,unsigned int mode)37 File::File(const std::string &path, unsigned int mode) : mode_(mode)
38 {
39 if (path.empty()) {
40 return;
41 }
42
43 if ((mode_ & READ) != 0) {
44 OpenByRead(path);
45 return;
46 }
47
48 if ((mode_ & WRITE) != 0) {
49 fd_ = fopen(path.c_str(), "w+");
50 } else if ((mode_ & APPEND) != 0) {
51 fd_ = fopen(path.c_str(), "a+");
52 }
53
54 if (fd_ == nullptr) {
55 Logger::E(TAG, "can't open '%s'", path.c_str());
56 return;
57 }
58
59 path_ = RealPath(path);
60 }
61
~File()62 File::~File()
63 {
64 Close();
65 }
66
OpenByRead(const std::string & path)67 void File::OpenByRead(const std::string &path)
68 {
69 if (!CheckValid(path)) {
70 Logger::E(TAG, "failed to check path '%s'", path.c_str());
71 return;
72 }
73
74 std::string realPath = RealPath(path);
75 if (realPath.empty()) {
76 Logger::E(TAG, "invalid path '%s'", path.c_str());
77 return;
78 }
79
80 fd_ = fopen(realPath.c_str(), "r");
81 if (fd_ == nullptr) {
82 Logger::E(TAG, "can't open '%s'", realPath.c_str());
83 return;
84 }
85
86 path_ = realPath;
87 PeekChar();
88 }
89
GetChar()90 char File::GetChar()
91 {
92 char c = PeekChar();
93
94 if (position_ + 1 <= size_) {
95 position_++;
96
97 if (c != '\n') {
98 columnNo_++;
99 } else {
100 columnNo_ = 1;
101 lineNo_++;
102 }
103 }
104 return c;
105 }
106
PeekChar()107 char File::PeekChar()
108 {
109 if (position_ + 1 > size_) {
110 size_t size = Read();
111 if (size == 0) {
112 isEof_ = true;
113 }
114 }
115
116 return buffer_[position_];
117 }
118
IsEof() const119 bool File::IsEof() const
120 {
121 return isEof_ || buffer_[position_] == static_cast<char>(-1);
122 }
123
Read()124 size_t File::Read()
125 {
126 if (isEof_ || isError_) {
127 return -1;
128 }
129
130 std::fill(buffer_, buffer_ + BUFFER_SIZE, 0);
131 size_t count = fread(buffer_, 1, BUFFER_SIZE - 1, fd_);
132 if (count < BUFFER_SIZE - 1) {
133 isError_ = ferror(fd_) != 0;
134 buffer_[count] = -1;
135 }
136 size_ = count;
137 position_ = 0;
138 if ((count == 0) || (count >= BUFFER_SIZE)) {
139 return -1;
140 }
141 return count;
142 }
143
ReadData(void * data,size_t size) const144 size_t File::ReadData(void *data, size_t size) const
145 {
146 if (data == nullptr || size == 0) {
147 return 0;
148 }
149
150 if (fd_ == nullptr) {
151 return 0;
152 }
153
154 return fread(data, 1, size, fd_);
155 }
156
WriteData(const void * data,size_t size) const157 bool File::WriteData(const void *data, size_t size) const
158 {
159 if (data == nullptr || size == 0) {
160 return true;
161 }
162
163 if (fd_ == nullptr || !(mode_ & (WRITE | APPEND))) {
164 return false;
165 }
166
167 size_t count = fwrite(data, size, 1, fd_);
168 return count == 1;
169 }
170
Flush() const171 void File::Flush() const
172 {
173 if ((mode_ & (WRITE | APPEND)) && fd_ != nullptr) {
174 fflush(fd_);
175 }
176 }
177
Reset() const178 bool File::Reset() const
179 {
180 if (fd_ == nullptr) {
181 return false;
182 }
183
184 return fseek(fd_, 0, SEEK_SET) == 0;
185 }
186
Skip(long size) const187 bool File::Skip(long size) const
188 {
189 if (fd_ == nullptr) {
190 return false;
191 }
192
193 return fseek(fd_, size, SEEK_CUR) == 0;
194 }
195
Close()196 void File::Close()
197 {
198 if (fd_ != nullptr) {
199 fclose(fd_);
200 fd_ = nullptr;
201 }
202 }
203
CreateParentDir(const std::string & path)204 bool File::CreateParentDir(const std::string &path)
205 {
206 if (access(path.c_str(), F_OK | R_OK | W_OK) == 0) {
207 return true;
208 }
209
210 size_t pos = 1;
211 while ((pos = path.find(SEPARATOR, pos)) != std::string::npos) {
212 std::string partPath = StringHelper::SubStr(path, 0, pos);
213 partPath += SEPARATOR;
214 if (File::CreatePartDir(partPath) == false) {
215 return false;
216 }
217 pos += 1;
218 }
219 return true;
220 }
221
CreatePartDir(const std::string & partPath)222 bool File::CreatePartDir(const std::string &partPath)
223 {
224 struct stat st;
225 if (stat(partPath.c_str(), &st) < 0) {
226 if (errno != ENOENT) {
227 return false;
228 }
229
230 #ifndef __MINGW32__
231 if (mkdir(partPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
232 #else
233 if (mkdir(partPath.c_str()) < 0) {
234 #endif
235 return false;
236 }
237 } else if (!S_ISDIR(st.st_mode)) {
238 return false;
239 }
240 return true;
241 }
242
243 std::string File::AdapterPath(const std::string &path)
244 {
245 #ifndef __MINGW32__
246 std::string newPath = StringHelper::Replace(path, '\\', '/');
247 #else
248 std::string newPath = StringHelper::Replace(path, '/', '\\');
249 #endif
250
251 // "foo/v1_0//ifoo.h" -> "foo/v1_0/ifoo.h"
252 StringBuilder adapterPath;
253 bool hasSep = false;
254 for (size_t i = 0; i < newPath.size(); i++) {
255 char c = newPath[i];
256 if (c == SEPARATOR) {
257 if (hasSep) {
258 continue;
259 }
260 adapterPath.Append(c);
261 hasSep = true;
262 } else {
263 adapterPath.Append(c);
264 hasSep = false;
265 }
266 }
267 return adapterPath.ToString();
268 }
269
270 std::string File::AdapterRealPath(const std::string &path)
271 {
272 if (path.empty()) {
273 return "";
274 }
275 return RealPath(File::AdapterPath(path));
276 }
277
278 std::string File::RealPath(const std::string &path)
279 {
280 if (path.empty()) {
281 return "";
282 }
283
284 char realPath[PATH_MAX + 1];
285 #ifdef __MINGW32__
286 char *absPath = _fullpath(realPath, path.c_str(), PATH_MAX);
287 #else
288 char *absPath = realpath(path.c_str(), realPath);
289 #endif
290 return absPath == nullptr ? "" : absPath;
291 }
292
293 bool File::CheckValid(const std::string &path)
294 {
295 if (access(path.c_str(), F_OK | R_OK | W_OK) != 0) {
296 return false;
297 }
298
299 struct stat st;
300 if (stat(path.c_str(), &st) < 0) {
301 return false;
302 }
303
304 if (S_ISDIR(st.st_mode)) {
305 return false;
306 }
307
308 return true;
309 }
310
311 std::set<std::string> File::FindFiles(const std::string &rootDir)
312 {
313 if (rootDir.empty()) {
314 return std::set<std::string>();
315 }
316
317 std::set<std::string> files;
318 std::queue<std::string> dirs;
319 dirs.push(rootDir);
320 while (!dirs.empty()) {
321 std::string dirPath = dirs.front().back() == SEPARATOR ? dirs.front() : dirs.front() + SEPARATOR;
322 dirs.pop();
323 DIR *dir = opendir(dirPath.c_str());
324 if (dir == nullptr) {
325 Logger::E(TAG, "failed to open '%s', errno:%d", dirPath.c_str(), errno);
326 continue;
327 }
328
329 struct dirent *dirInfo = readdir(dir);
330 for (; dirInfo != nullptr; dirInfo = readdir(dir)) {
331 if (strcmp(dirInfo->d_name, ".") == 0 || strcmp(dirInfo->d_name, "..") == 0) {
332 continue;
333 }
334 #ifndef __MINGW32__
335 if (dirInfo->d_type == DT_REG && StringHelper::EndWith(dirInfo->d_name, ".idl")) {
336 std::string filePath = dirPath + dirInfo->d_name;
337 files.insert(filePath);
338 continue;
339 }
340
341 if (dirInfo->d_type == DT_DIR) {
342 dirs.emplace(dirPath + dirInfo->d_name);
343 continue;
344 }
345 #else
346 std::string filePath = dirPath + dirInfo->d_name;
347 struct stat fileInfo;
348 if ((stat(filePath.c_str(), &fileInfo) == 0) && S_ISREG(fileInfo.st_mode)) {
349 files.insert(filePath);
350 }
351 #endif
352 }
353 closedir(dir);
354 }
355
356 return files;
357 }
358
359 size_t File::GetHashKey()
360 {
361 StringBuilder fileStr;
362 while (!IsEof()) {
363 fileStr.Append(GetChar());
364 }
365
366 return std::hash<std::string>()(fileStr.ToString());
367 }
368 } // namespace Idl
369 } // namespace OHOS