1 /*
2 * Copyright (c) 2021 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 <functional>
15 #include <string>
16 #include <algorithm>
17 #include <sys/stat.h>
18 #include <unistd.h>
19
20 #include "util/common.h"
21 #include "util/logger.h"
22 #include "util/string_helper.h"
23 #include "util/string_builder.h"
24
25 namespace OHOS {
26 namespace HDI {
File(const std::string & path,unsigned int mode)27 File::File(const std::string &path, unsigned int mode) : mode_(mode)
28 {
29 if (path.empty()) {
30 return;
31 }
32
33 if (mode_ & READ) {
34 OpenByRead(path);
35 return;
36 }
37
38 if (mode_ & WRITE) {
39 fd_ = fopen(path.c_str(), "w+");
40 } else if (mode_ & APPEND) {
41 fd_ = fopen(path.c_str(), "a+");
42 }
43
44 if (fd_ == nullptr) {
45 Logger::E(TAG, "can't open '%s'", path.c_str());
46 return;
47 }
48
49 path_ = RealPath(path);
50 }
51
~File()52 File::~File()
53 {
54 Close();
55 }
56
OpenByRead(const std::string & path)57 void File::OpenByRead(const std::string &path)
58 {
59 if (!CheckValid(path)) {
60 Logger::E(TAG, "failed to check path '%s'", path.c_str());
61 return;
62 }
63
64 std::string realPath = RealPath(path);
65 if (realPath.empty()) {
66 Logger::E(TAG, "invalid path '%s'", path.c_str());
67 return;
68 }
69
70 fd_ = fopen(realPath.c_str(), "r");
71 if (fd_ == nullptr) {
72 Logger::E(TAG, "can't open '%s'", realPath.c_str());
73 return;
74 }
75
76 path_ = realPath;
77 }
78
GetChar()79 char File::GetChar()
80 {
81 char c = PeekChar();
82
83 if (position_ + 1 <= size_) {
84 position_++;
85
86 if (c != '\n') {
87 columnNo_++;
88 } else {
89 columnNo_ = 1;
90 lineNo_++;
91 }
92 }
93 return c;
94 }
95
PeekChar()96 char File::PeekChar()
97 {
98 if (position_ + 1 > size_) {
99 size_t size = Read();
100 if (size == 0) {
101 isEof_ = true;
102 }
103 }
104
105 return buffer_[position_];
106 }
107
IsEof() const108 bool File::IsEof() const
109 {
110 return isEof_ || buffer_[position_] == -1;
111 }
112
Read()113 size_t File::Read()
114 {
115 if (isEof_ || isError_) {
116 return -1;
117 }
118
119 std::fill(buffer_, buffer_ + BUFFER_SIZE, 0);
120 size_t count = fread(buffer_, 1, BUFFER_SIZE - 1, fd_);
121 if (count < BUFFER_SIZE - 1) {
122 isError_ = ferror(fd_) != 0;
123 buffer_[count] = -1;
124 }
125 size_ = count;
126 position_ = 0;
127 return count;
128 }
129
ReadData(void * data,size_t size) const130 size_t File::ReadData(void *data, size_t size) const
131 {
132 if (data == nullptr || size == 0) {
133 return 0;
134 }
135
136 if (fd_ == nullptr) {
137 return 0;
138 }
139
140 return fread(data, 1, size, fd_);
141 }
142
WriteData(const void * data,size_t size) const143 bool File::WriteData(const void *data, size_t size) const
144 {
145 if (data == nullptr || size == 0) {
146 return true;
147 }
148
149 if (fd_ == nullptr || !(mode_ & (WRITE | APPEND))) {
150 return false;
151 }
152
153 size_t count = fwrite(data, size, 1, fd_);
154 return count == 1;
155 }
156
Flush()157 void File::Flush()
158 {
159 if ((mode_ & (WRITE | APPEND)) && fd_ != nullptr) {
160 fflush(fd_);
161 }
162 }
163
Reset()164 bool File::Reset()
165 {
166 if (fd_ == nullptr) {
167 return false;
168 }
169
170 return fseek(fd_, 0, SEEK_SET) == 0;
171 }
172
Skip(long size)173 bool File::Skip(long size)
174 {
175 if (fd_ == nullptr) {
176 return false;
177 }
178
179 return fseek(fd_, size, SEEK_CUR) == 0;
180 }
181
Close()182 void File::Close()
183 {
184 if (fd_ != nullptr) {
185 fclose(fd_);
186 fd_ = nullptr;
187 }
188 }
189
CreateParentDir(const std::string & path)190 bool File::CreateParentDir(const std::string &path)
191 {
192 if (!access(path.c_str(), F_OK | R_OK | W_OK)) {
193 return true;
194 }
195
196 size_t pos = 1;
197 while ((pos = path.find(SEPARATOR, pos)) != std::string::npos) {
198 std::string partPath = StringHelper::SubStr(path, 0, pos);
199 struct stat st;
200 if (stat(partPath.c_str(), &st) < 0) {
201 if (errno != ENOENT) {
202 return false;
203 }
204
205 #ifndef __MINGW32__
206 if (mkdir(partPath.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
207 #else
208 if (mkdir(partPath.c_str()) < 0) {
209 #endif
210 return false;
211 }
212 } else if (!S_ISDIR(st.st_mode)) {
213 return false;
214 }
215 pos += 1;
216 }
217 return true;
218 }
219
220 std::string File::AdapterPath(const std::string &path)
221 {
222 #ifndef __MINGW32__
223 std::string newPath = StringHelper::Replace(path, '\\', '/');
224 #else
225 std::string newPath = StringHelper::Replace(path, '/', '\\');
226 #endif
227
228 // "foo/v1_0//ifoo.h" -> "foo/v1_0/ifoo.h"
229 StringBuilder adapterPath;
230 bool hasSep = false;
231 for (size_t i = 0; i < newPath.size(); i++) {
232 char c = newPath[i];
233 if (c == SEPARATOR) {
234 if (hasSep) {
235 continue;
236 }
237 adapterPath.Append(c);
238 hasSep = true;
239 } else {
240 adapterPath.Append(c);
241 hasSep = false;
242 }
243 }
244 return adapterPath.ToString();
245 }
246
247 std::string File::AdapterRealPath(const std::string &path)
248 {
249 if (path.empty()) {
250 return "";
251 }
252 return RealPath(File::AdapterPath(path));
253 }
254
255 std::string File::RealPath(const std::string &path)
256 {
257 if (path.empty()) {
258 return "";
259 }
260
261 char realPath[PATH_MAX + 1];
262 #ifdef __MINGW32__
263 char *absPath = _fullpath(realPath, path.c_str(), PATH_MAX);
264 #else
265 char *absPath = realpath(path.c_str(), realPath);
266 #endif
267 return absPath == nullptr ? "" : absPath;
268 }
269
270 bool File::CheckValid(const std::string &path)
271 {
272 if (access(path.c_str(), F_OK | R_OK | W_OK)) {
273 return false;
274 }
275
276 struct stat st;
277 if (stat(path.c_str(), &st) < 0) {
278 return false;
279 }
280
281 if (S_ISDIR(st.st_mode)) {
282 return false;
283 }
284
285 return true;
286 }
287
288 size_t File::GetHashKey()
289 {
290 StringBuilder fileStr;
291 while (!IsEof()) {
292 fileStr.Append(GetChar());
293 }
294
295 return std::hash<std::string>()(fileStr.ToString());
296 }
297 } // namespace HDI
298 } // namespace OHOS