• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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