• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <unistd.h>
27 #include <sstream>
28 #include <sys/stat.h>
29 #include <sys/types.h>
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     Close();
81     fd_ = fopen(realPath.c_str(), "r");
82     if (fd_ == nullptr) {
83         Logger::E(TAG, "can't open '%s'", realPath.c_str());
84         return;
85     }
86 
87     path_ = realPath;
88     PeekChar();
89 }
90 
GetChar()91 char File::GetChar()
92 {
93     char c = PeekChar();
94 
95     if (position_ + 1 <= size_) {
96         position_++;
97 
98         if (c != '\n') {
99             columnNo_++;
100         } else {
101             columnNo_ = 1;
102             lineNo_++;
103         }
104     }
105     return c;
106 }
107 
PeekChar()108 char File::PeekChar()
109 {
110     if (position_ + 1 > size_) {
111         size_t size = Read();
112         if (size == 0) {
113             isEof_ = true;
114         }
115     }
116 
117     return buffer_[position_];
118 }
119 
NextChar()120 char File::NextChar()
121 {
122     if (position_ + 1 >= size_) {
123         size_t size = Read();
124         if (size == 0) {
125             isEof_ = true;
126             return '\0';
127         }
128     }
129 
130     return buffer_[position_ + 1];
131 }
132 
IsEof() const133 bool File::IsEof() const
134 {
135     return isEof_ || buffer_[position_] == static_cast<char>(-1);
136 }
137 
Read()138 size_t File::Read()
139 {
140     if (isEof_ || isError_) {
141         return -1;
142     }
143 
144     std::fill(buffer_, buffer_ + BUFFER_SIZE, 0);
145     size_t count = fread(buffer_, 1, BUFFER_SIZE - 1, fd_);
146     if (count < BUFFER_SIZE - 1) {
147         isError_ = ferror(fd_) != 0;
148         buffer_[count] = -1;
149     }
150     size_ = count;
151     position_ = 0;
152     if ((count == 0) || (count >= BUFFER_SIZE)) {
153         return -1;
154     }
155     return count;
156 }
157 
ReadData(void * data,size_t size) const158 size_t File::ReadData(void *data, size_t size) const
159 {
160     if (data == nullptr || size == 0) {
161         return 0;
162     }
163 
164     if (fd_ == nullptr) {
165         return 0;
166     }
167 
168     return fread(data, 1, size, fd_);
169 }
170 
WriteData(const void * data,size_t size) const171 bool File::WriteData(const void *data, size_t size) const
172 {
173     if (data == nullptr || size == 0) {
174         return true;
175     }
176 
177     if (fd_ == nullptr || !(mode_ & (WRITE | APPEND))) {
178         return false;
179     }
180 
181     size_t count = fwrite(data, size, 1, fd_);
182     return count == 1;
183 }
184 
Flush() const185 void File::Flush() const
186 {
187     if ((mode_ & (WRITE | APPEND)) && fd_ != nullptr) {
188         fflush(fd_);
189     }
190 }
191 
Reset() const192 bool File::Reset() const
193 {
194     if (fd_ == nullptr) {
195         return false;
196     }
197 
198     return fseek(fd_, 0, SEEK_SET) == 0;
199 }
200 
Skip(long size) const201 bool File::Skip(long size) const
202 {
203     if (fd_ == nullptr) {
204         return false;
205     }
206 
207     return fseek(fd_, size, SEEK_CUR) == 0;
208 }
209 
Close()210 void File::Close()
211 {
212     if (fd_ != nullptr) {
213         fclose(fd_);
214         fd_ = nullptr;
215     }
216 }
217 
CreateParentDir(const std::string & path)218 bool File::CreateParentDir(const std::string &path)
219 {
220     if (access(path.c_str(), F_OK | R_OK | W_OK) == 0) {
221         return true;
222     }
223 
224     size_t pos = 1;
225     while ((pos = path.find(SEPARATOR, pos)) != std::string::npos) {
226         std::string partPath = StringHelper::SubStr(path, 0, pos);
227         partPath += SEPARATOR;
228         if (File::CreatePartDir(partPath) == false) {
229             return false;
230         }
231         pos += 1;
232     }
233     return true;
234 }
235 
CreatePartDir(const std::string & partPath)236 bool File::CreatePartDir(const std::string &partPath)
237 {
238     struct stat st;
239     if (stat(partPath.c_str(), &st) < 0) {
240         if (errno != ENOENT) {
241             return false;
242         }
243 
244 #ifndef __MINGW32__
245         if (mkdir(partPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
246 #else
247         if (mkdir(partPath.c_str()) < 0) {
248 #endif
249             return false;
250         }
251     } else if (!S_ISDIR(st.st_mode)) {
252         return false;
253     }
254     return true;
255 }
256 
257 std::string File::AdapterPath(const std::string &path)
258 {
259 #ifndef __MINGW32__
260     std::string newPath = StringHelper::Replace(path, '\\', '/');
261 #else
262     std::string newPath = StringHelper::Replace(path, '/', '\\');
263 #endif
264 
265     // "foo/v1_0//ifoo.h" -> "foo/v1_0/ifoo.h"
266     StringBuilder adapterPath;
267     bool hasSep = false;
268     for (size_t i = 0; i < newPath.size(); i++) {
269         char c = newPath[i];
270         if (c == SEPARATOR) {
271             if (hasSep) {
272                 continue;
273             }
274             adapterPath.Append(c);
275             hasSep = true;
276         } else {
277             adapterPath.Append(c);
278             hasSep = false;
279         }
280     }
281     return adapterPath.ToString();
282 }
283 
284 std::string File::AdapterRealPath(const std::string &path)
285 {
286     if (path.empty()) {
287         return "";
288     }
289     return RealPath(File::AdapterPath(path));
290 }
291 
292 std::string File::RealPath(const std::string &path)
293 {
294     if (path.empty()) {
295         return "";
296     }
297 
298     char realPath[PATH_MAX + 1];
299 #ifdef __MINGW32__
300     char *absPath = _fullpath(realPath, path.c_str(), PATH_MAX);
301 #else
302     char *absPath = realpath(path.c_str(), realPath);
303 #endif
304     return absPath == nullptr ? "" : absPath;
305 }
306 
307 std::string File::CanonicalPath(const std::string &path)
308 {
309     std::istringstream ss(path);
310     std::string segment;
311     std::vector<std::string> pathStack;
312 
313     while (std::getline(ss, segment, SEPARATOR)) {
314         if (segment == "..") {
315             if (!pathStack.empty()) {
316                 pathStack.pop_back();
317             }
318         } else if (!segment.empty() && segment != ".") {
319             pathStack.push_back(segment);
320         }
321     }
322 
323     std::string normalizedPath;
324     for (const auto &s : pathStack) {
325         normalizedPath += std::string(1, SEPARATOR) + s;
326     }
327 #ifdef __MINGW32__
328     normalizedPath = normalizedPath.substr(1);
329 #endif
330 
331     return normalizedPath.empty() ? std::string(1, SEPARATOR) : normalizedPath;
332 }
333 
334 std::string File::AbsolutePath(const std::string &path)
335 {
336     if (!path.empty() && (path[0] == SEPARATOR || path[1] == ':')) {
337         return path;
338     }
339     char buffer[PATH_MAX + 1];
340 #ifdef __MINGW32__
341     if (_getcwd(buffer, sizeof(buffer)) != nullptr) {
342 #else
343     if (getcwd(buffer, sizeof(buffer)) != nullptr) {
344 #endif
345         return std::string(buffer) + std::string(1, SEPARATOR) + path;
346     }
347     return "";
348 }
349 
350 std::vector<std::string> File::SplitPath(const std::string& path)
351 {
352     std::vector<std::string> components;
353     std::istringstream stream(path);
354     std::string segment;
355 
356     while (std::getline(stream, segment, SEPARATOR)) {
357         if (!segment.empty()) {
358             components.push_back(segment);
359         }
360     }
361 
362     return components;
363 }
364 
365 std::string File::RelativePath(const std::string& pathA, const std::string& pathB)
366 {
367     std::vector<std::string> componentsA = SplitPath(pathA);
368     std::vector<std::string> componentsB = SplitPath(pathB);
369 
370     size_t i = 0;
371     while (i < componentsA.size() && i < componentsB.size() && componentsA[i] == componentsB[i]) {
372         i++;
373     }
374 
375     std::string relativePath;
376 
377     for (size_t j = i; j < componentsB.size(); ++j) {
378         relativePath += ".." + std::string(1, SEPARATOR);
379     }
380 
381     for (size_t j = i; j < componentsA.size(); ++j) {
382         relativePath += componentsA[j] + std::string(1, SEPARATOR);
383     }
384 
385     if (!relativePath.empty() && relativePath.back() == SEPARATOR) {
386         relativePath.pop_back();
387     }
388 
389     return relativePath;
390 }
391 
392 bool File::CheckValid(const std::string &path)
393 {
394     if (access(path.c_str(), F_OK | R_OK | W_OK) != 0) {
395         return false;
396     }
397 
398     struct stat st;
399     if (stat(path.c_str(), &st) < 0) {
400         return false;
401     }
402 
403     if (S_ISDIR(st.st_mode)) {
404         return false;
405     }
406 
407     return true;
408 }
409 
410 std::set<std::string> File::FindFiles(const std::string &rootDir)
411 {
412     if (rootDir.empty()) {
413         return std::set<std::string>();
414     }
415 
416     std::set<std::string> files;
417     std::queue<std::string> dirs;
418     dirs.push(rootDir);
419     while (!dirs.empty()) {
420         std::string dirPath = dirs.front().back() == SEPARATOR ? dirs.front() : dirs.front() + SEPARATOR;
421         dirs.pop();
422         DIR *dir = opendir(dirPath.c_str());
423         if (dir == nullptr) {
424             Logger::E(TAG, "failed to open '%s', errno:%d", dirPath.c_str(), errno);
425             continue;
426         }
427 
428         struct dirent *dirInfo = readdir(dir);
429         for (; dirInfo != nullptr; dirInfo = readdir(dir)) {
430             if (strcmp(dirInfo->d_name, ".") == 0 || strcmp(dirInfo->d_name, "..") == 0) {
431                 continue;
432             }
433 #ifndef __MINGW32__
434             if (dirInfo->d_type == DT_REG && StringHelper::EndWith(dirInfo->d_name, ".idl")) {
435                 std::string filePath = dirPath + dirInfo->d_name;
436                 files.insert(filePath);
437                 continue;
438             }
439 
440             if (dirInfo->d_type == DT_DIR) {
441                 dirs.emplace(dirPath + dirInfo->d_name);
442                 continue;
443             }
444 #else
445             std::string filePath = dirPath + dirInfo->d_name;
446             struct stat fileInfo;
447             if ((stat(filePath.c_str(), &fileInfo) == 0) && S_ISREG(fileInfo.st_mode)) {
448                 files.insert(filePath);
449             }
450 #endif
451         }
452         closedir(dir);
453     }
454 
455     return files;
456 }
457 
458 size_t File::GetHashKey()
459 {
460     StringBuilder fileStr;
461     while (!IsEof()) {
462         fileStr.Append(GetChar());
463     }
464 
465     return std::hash<std::string>()(fileStr.ToString());
466 }
467 } // namespace Idl
468 } // namespace OHOS