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