1 /*
2 * Copyright (c) 2022 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 #include "file_path.h"
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <unistd.h>
19 #include <dirent.h>
20 #include "zip_utils.h"
21 #include "directory_ex.h"
22 #include "app_log_wrapper.h"
23
24 using namespace std;
25 using namespace OHOS::AppExecFwk;
26 namespace OHOS {
27 namespace AppExecFwk {
28 namespace LIBZIP {
29 namespace {
30 const std::string SEPARATOR = "/";
31 const std::string ZIP = ".zip";
32 const std::int32_t ZIP_SIZE = 4;
33 }
34 const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
35 const size_t FilePath::kSeparatorsLength = arraysize(kSeparators);
36 const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
37 const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
38 const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
39
FilePath()40 FilePath::FilePath()
41 {}
42
FilePath(const FilePath & that)43 FilePath::FilePath(const FilePath &that) : path_(that.path_)
44 {}
45
FilePath(const std::string & path)46 FilePath::FilePath(const std::string &path) : path_(path)
47 {}
48
~FilePath()49 FilePath::~FilePath()
50 {}
51
operator =(const FilePath & that)52 FilePath &FilePath::operator=(const FilePath &that)
53 {
54 if (&that != this) {
55 path_ = that.path_;
56 }
57 return *this;
58 }
59
operator ==(const FilePath & that) const60 bool FilePath::operator==(const FilePath &that) const
61 {
62 return path_ == that.path_;
63 }
64
operator !=(const FilePath & that) const65 bool FilePath::operator!=(const FilePath &that) const
66 {
67 return path_ != that.path_;
68 }
69
operator <(const FilePath & that) const70 bool FilePath::operator<(const FilePath &that) const
71 {
72 return path_ < that.path_;
73 }
74
FromUTF8Unsafe(const std::string & utf8)75 FilePath FilePath::FromUTF8Unsafe(const std::string &utf8)
76 {
77 return FilePath(utf8);
78 }
79
ReferencesParent()80 bool FilePath::ReferencesParent()
81 {
82 std::vector<std::string> components;
83 GetComponents(components);
84
85 for (size_t i = 0; i < components.size(); i++) {
86 if (components[i].find_first_not_of(FILE_PATH_LITERAL(". \n\r\t")) == std::string::npos &&
87 components[i].find(kParentDirectory) != std::string::npos) {
88 return true;
89 }
90 }
91 return false;
92 }
93
GetComponents(std::vector<std::string> & components)94 void FilePath::GetComponents(std::vector<std::string> &components)
95 {
96 components.clear();
97 if (path_.empty()) {
98 return;
99 }
100
101 FilePath current = *this;
102 FilePath base;
103 // Capture path components.
104 while (current != current.DirName()) {
105 base = current.BaseName();
106 if (!AreAllSeparators(base.path_))
107 components.push_back(base.path_);
108 current = current.DirName();
109 }
110
111 // Capture root, if any.
112 base = current.BaseName();
113 if (!base.path_.empty() && base.path_ != kCurrentDirectory) {
114 components.push_back(current.BaseName().path_);
115 }
116 }
117
DirName()118 FilePath FilePath::DirName()
119 {
120 FilePath newPath(path_);
121 newPath.StripTrailingSeparatorsInternal();
122
123 std::string::size_type lastSeparator =
124 newPath.path_.find_last_of(kSeparators, std::string::npos, kSeparatorsLength - 1);
125 std::string::size_type zero = 0;
126 std::string::size_type one = 1;
127 std::string::size_type two = 2;
128
129 if (lastSeparator == std::string::npos) {
130 // path_ is in the current directory.
131 newPath.path_.resize(zero);
132 } else if (lastSeparator == zero) {
133 // path_ is in the root directory.
134 newPath.path_.resize(one);
135 } else if (lastSeparator == one && IsSeparator(newPath.path_[zero])) {
136 // path_ is in "//" (possibly with a drive letter); leave the double
137 // separator intact indicating alternate root.
138 newPath.path_.resize(two);
139 } else {
140 // path_ is somewhere else, trim the basename.
141 newPath.path_.resize(lastSeparator);
142 }
143
144 newPath.StripTrailingSeparatorsInternal();
145 if (!newPath.path_.length()) {
146 newPath.path_ = kCurrentDirectory;
147 }
148
149 return newPath;
150 }
151
BaseName()152 FilePath FilePath::BaseName()
153 {
154 FilePath newPath(path_);
155 newPath.StripTrailingSeparatorsInternal();
156
157 // Keep everything after the final separator, but if the pathname is only
158 // one character and it's a separator, leave it alone.
159 std::string::size_type lastSeparator =
160 newPath.path_.find_last_of(kSeparators, std::string::npos, kSeparatorsLength - 1);
161 if (lastSeparator != std::string::npos && lastSeparator < newPath.path_.length() - 1) {
162 newPath.path_.erase(0, lastSeparator + 1);
163 }
164
165 return newPath;
166 }
167
StripTrailingSeparatorsInternal()168 void FilePath::StripTrailingSeparatorsInternal()
169 {
170 if (path_.size() == 0) {
171 return;
172 }
173 uint32_t one = 1;
174 uint32_t two = 2;
175 uint32_t start = 1;
176 std::string::size_type lastStripped = std::string::npos;
177 for (std::string::size_type pos = path_.length(); pos > start && FilePath::IsSeparator(path_[pos - one]); --pos) {
178 if (pos != start + one || lastStripped == start + two || !FilePath::IsSeparator(path_[start - one])) {
179 path_.resize(pos - one);
180 lastStripped = pos;
181 }
182 }
183 }
184
AreAllSeparators(const std::string & input)185 bool FilePath::AreAllSeparators(const std::string &input)
186 {
187 for (std::string::const_iterator it = input.begin(); it != input.end(); ++it) {
188 if (!FilePath::IsSeparator(*it)) {
189 return false;
190 }
191 }
192
193 return true;
194 }
195
IsAbsolute()196 bool FilePath::IsAbsolute()
197 {
198 return path_.length() > 0 && FilePath::IsSeparator(path_[0]);
199 }
200
Value()201 std::string FilePath::Value()
202 {
203 return path_;
204 }
IsSeparator(CharType character)205 bool FilePath::IsSeparator(CharType character)
206 {
207 for (size_t i = 0; i < kSeparatorsLength - 1; ++i) {
208 if (character == kSeparators[i]) {
209 return true;
210 }
211 }
212 return false;
213 }
CreateDirectory(const FilePath & fullPath)214 bool FilePath::CreateDirectory(const FilePath &fullPath)
215 {
216 std::vector<FilePath> subpaths;
217
218 // Collect a list of all parent directories.
219 FilePath lastPath = fullPath;
220 subpaths.push_back(fullPath);
221 for (FilePath path = const_cast<FilePath &>(fullPath).DirName(); path.Value() != lastPath.Value();
222 path = path.DirName()) {
223 subpaths.push_back(path);
224 lastPath = path;
225 }
226 mode_t rootMode = 0777;
227 // Iterate through the parents and create the missing ones.
228 for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin(); i != subpaths.rend(); ++i) {
229 if (DirectoryExists(*i)) {
230 continue;
231 }
232 if (mkdir(i->Value().c_str(), rootMode) == 0) {
233 continue;
234 }
235
236 if (!DirectoryExists(*i)) {
237 return false;
238 }
239 }
240 return true;
241 }
242 // static
DirectoryExists(const FilePath & path)243 bool FilePath::DirectoryExists(const FilePath &path)
244 {
245 struct stat fileInfo;
246 if (stat(const_cast<FilePath &>(path).Value().c_str(), &fileInfo) == 0) {
247 return S_ISDIR(fileInfo.st_mode);
248 }
249
250 APP_LOGI("!!!stat returns an error.!!!");
251 return false;
252 }
IsDir(const FilePath & path)253 bool FilePath::IsDir(const FilePath &path)
254 {
255 std::string mPath(const_cast<FilePath &>(path).Value());
256 if (mPath.empty() || mPath == kCurrentDirectory || mPath == kParentDirectory) {
257 return true;
258 } else {
259 struct stat fileInfo;
260 int ret = stat(mPath.c_str(), &fileInfo);
261 return (ret == 0 && S_ISDIR(fileInfo.st_mode));
262 }
263 }
264
PathIsValid(const FilePath & path)265 bool FilePath::PathIsValid(const FilePath &path)
266 {
267 return access(const_cast<FilePath &>(path).Value().c_str(), F_OK) == 0;
268 }
269
270 // Returns a FilePath by appending a separator and the supplied path
271 // component to this object's path. Append takes care to avoid adding
272 // excessive separators if this object's path already ends with a separator.
273 // If this object's path is kCurrentDirectory, a new FilePath corresponding
274 // only to |component| is returned. |component| must be a relative path;
275 // it is an error to pass an absolute path.
Append(const std::string & component)276 FilePath FilePath::Append(const std::string &component)
277 {
278 if (component.empty()) {
279 FilePath pathOrg(path_);
280 return pathOrg;
281 }
282
283 std::string newPathString;
284 // empty
285 if (Value().empty()) {
286 newPathString += component;
287 } else if (EndsWith(Value(), SEPARATOR)) {
288 if (StartsWith(component, SEPARATOR)) {
289 newPathString = component.substr(1, component.size());
290 } else {
291 newPathString = path_ + SEPARATOR + component;
292 }
293 } else {
294 if (StartsWith(component, SEPARATOR)) {
295 newPathString = path_ + component;
296 } else {
297 newPathString = path_ + SEPARATOR + component;
298 }
299 }
300
301 FilePath newPath(newPathString);
302 return newPath;
303 }
304
Append(FilePath & component)305 FilePath FilePath::Append(FilePath &component)
306 {
307 if (component.path_.empty()) {
308 FilePath pathOrg(path_);
309 return pathOrg;
310 }
311
312 return Append(component.path_);
313 }
314
AppendSeparator(void)315 void FilePath::AppendSeparator(void)
316 {
317 if (path_.empty()) {
318 path_ = SEPARATOR;
319 } else {
320 path_ += SEPARATOR;
321 }
322 }
323 // If IsParent(child) holds, appends to path (if non-NULL) the
324 // relative path to child and returns true.
AppendRelativePath(const FilePath & child,FilePath * path)325 bool FilePath::AppendRelativePath(const FilePath &child, FilePath *path)
326 {
327 FilePath childPath = child;
328 std::vector<std::string> parentComponents;
329 std::vector<std::string> childComponents;
330 GetComponents(parentComponents);
331 childPath.GetComponents(childComponents);
332
333 if (parentComponents.empty() || parentComponents.size() >= childComponents.size()) {
334 return false;
335 }
336
337 std::vector<std::string> parentComponentsReverse;
338 std::vector<std::string> childComponentsReverse;
339
340 std::vector<std::string>::reverse_iterator riter;
341 for (riter = parentComponents.rbegin(); riter != parentComponents.rend(); ++riter) {
342 parentComponentsReverse.push_back(*riter);
343 }
344 for (riter = childComponents.rbegin(); riter != childComponents.rend(); ++riter) {
345 childComponentsReverse.push_back(*riter);
346 }
347 std::vector<std::string>::const_iterator parentIt = parentComponentsReverse.begin();
348 std::vector<std::string>::const_iterator childIt = childComponentsReverse.begin();
349 while (parentIt != parentComponentsReverse.end()) {
350 if (*parentIt != *childIt)
351 return false;
352 ++parentIt;
353 ++childIt;
354 }
355
356 if (path != nullptr) {
357 // Relative paths do not include separator
358 if ((childIt != childComponentsReverse.end()) && (*childIt == SEPARATOR)) {
359 ++childIt;
360 }
361
362 for (; childIt != childComponentsReverse.end(); ++childIt) {
363 *path = path->Append(*childIt);
364 }
365 }
366 return true;
367 }
GetZipAllDirFiles(const std::string & path,std::vector<std::string> & files)368 bool FilePath::GetZipAllDirFiles(const std::string &path, std::vector<std::string> &files)
369 {
370 std::string pathStringWithDelimiter;
371 if (path.empty() || path == kCurrentDirectory || path == kParentDirectory) {
372 return true;
373 }
374 DIR *dir = opendir(path.c_str());
375 if (dir == nullptr) {
376 return false;
377 }
378
379 bool result = false;
380 while (true) {
381 result = true;
382 struct dirent *ptr = readdir(dir);
383 if (ptr == nullptr) {
384 break;
385 }
386 // current dir OR parent dir
387 if ((strcmp(ptr->d_name, kCurrentDirectory) == 0) || (strcmp(ptr->d_name, kParentDirectory) == 0)) {
388 continue;
389 } else if (ptr->d_type == DT_DIR) {
390 pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
391 std::vector<std::string> itemFiles;
392 GetZipAllDirFiles(pathStringWithDelimiter, itemFiles);
393
394 if (itemFiles.empty()) {
395 files.push_back(pathStringWithDelimiter);
396 } else {
397 files.insert(files.end(), itemFiles.begin(), itemFiles.end());
398 }
399 } else {
400 files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
401 }
402 }
403 closedir(dir);
404 return result;
405 }
406
CheckDestDirTail()407 std::string FilePath::CheckDestDirTail()
408 {
409 if (path_.substr(path_.size()-ZIP_SIZE, ZIP_SIZE) == ZIP) {
410 return path_;
411 } else {
412 return path_ + ZIP;
413 }
414 }
415 } // namespace LIBZIP
416 } // namespace AppExecFwk
417 } // namespace OHOS
418