• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_LOGD("!!!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 
PathIsReadable(const FilePath & path)270 bool FilePath::PathIsReadable(const FilePath &path)
271 {
272     return access(const_cast<FilePath &>(path).Value().c_str(), R_OK) == 0;
273 }
274 
275 // Returns a FilePath by appending a separator and the supplied path
276 // component to this object's path.  Append takes care to avoid adding
277 // excessive separators if this object's path already ends with a separator.
278 // If this object's path is kCurrentDirectory, a new FilePath corresponding
279 // only to |component| is returned.  |component| must be a relative path;
280 // it is an error to pass an absolute path.
Append(const std::string & component)281 FilePath FilePath::Append(const std::string &component)
282 {
283     if (component.empty()) {
284         FilePath pathOrg(path_);
285         return pathOrg;
286     }
287 
288     std::string newPathString;
289     // empty
290     if (Value().empty()) {
291         newPathString += component;
292     } else if (EndsWith(Value(), SEPARATOR)) {
293         if (StartsWith(component, SEPARATOR)) {
294             newPathString = component.substr(1, component.size());
295         } else {
296             newPathString = path_ + SEPARATOR + component;
297         }
298     } else {
299         if (StartsWith(component, SEPARATOR)) {
300             newPathString = path_ + component;
301         } else {
302             newPathString = path_ + SEPARATOR + component;
303         }
304     }
305 
306     FilePath newPath(newPathString);
307     return newPath;
308 }
309 
Append(FilePath & component)310 FilePath FilePath::Append(FilePath &component)
311 {
312     if (component.path_.empty()) {
313         FilePath pathOrg(path_);
314         return pathOrg;
315     }
316 
317     return Append(component.path_);
318 }
319 
AppendSeparator(void)320 void FilePath::AppendSeparator(void)
321 {
322     if (path_.empty()) {
323         path_ = SEPARATOR;
324     } else {
325         path_ += SEPARATOR;
326     }
327 }
328 // If IsParent(child) holds, appends to path (if non-NULL) the
329 // relative path to child and returns true.
AppendRelativePath(const FilePath & child,FilePath * path)330 bool FilePath::AppendRelativePath(const FilePath &child, FilePath *path)
331 {
332     FilePath childPath = child;
333     std::vector<std::string> parentComponents;
334     std::vector<std::string> childComponents;
335     GetComponents(parentComponents);
336     childPath.GetComponents(childComponents);
337 
338     if (parentComponents.empty() || parentComponents.size() >= childComponents.size()) {
339         return false;
340     }
341 
342     std::vector<std::string> parentComponentsReverse;
343     std::vector<std::string> childComponentsReverse;
344 
345     std::vector<std::string>::reverse_iterator riter;
346     for (riter = parentComponents.rbegin(); riter != parentComponents.rend(); ++riter) {
347         parentComponentsReverse.push_back(*riter);
348     }
349     for (riter = childComponents.rbegin(); riter != childComponents.rend(); ++riter) {
350         childComponentsReverse.push_back(*riter);
351     }
352     std::vector<std::string>::const_iterator parentIt = parentComponentsReverse.begin();
353     std::vector<std::string>::const_iterator childIt = childComponentsReverse.begin();
354     while (parentIt != parentComponentsReverse.end()) {
355         if (*parentIt != *childIt)
356             return false;
357         ++parentIt;
358         ++childIt;
359     }
360 
361     if (path != nullptr) {
362         // Relative paths do not include separator
363         if ((childIt != childComponentsReverse.end()) && (*childIt == SEPARATOR)) {
364             ++childIt;
365         }
366 
367         for (; childIt != childComponentsReverse.end(); ++childIt) {
368             *path = path->Append(*childIt);
369         }
370     }
371     return true;
372 }
GetZipAllDirFiles(const std::string & path,std::vector<std::string> & files)373 bool FilePath::GetZipAllDirFiles(const std::string &path, std::vector<std::string> &files)
374 {
375     std::string pathStringWithDelimiter;
376     if (path.empty() || path == kCurrentDirectory || path == kParentDirectory) {
377         return true;
378     }
379     DIR *dir = opendir(path.c_str());
380     if (dir == nullptr) {
381         return false;
382     }
383 
384     bool result = false;
385     while (true) {
386         result = true;
387         struct dirent *ptr = readdir(dir);
388         if (ptr == nullptr) {
389             break;
390         }
391         // current dir OR parent dir
392         if ((strcmp(ptr->d_name, kCurrentDirectory) == 0) || (strcmp(ptr->d_name, kParentDirectory) == 0)) {
393             continue;
394         } else if (ptr->d_type == DT_DIR) {
395             pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
396             std::vector<std::string> itemFiles;
397             GetZipAllDirFiles(pathStringWithDelimiter, itemFiles);
398 
399             if (itemFiles.empty()) {
400                 files.push_back(pathStringWithDelimiter);
401             } else {
402                 files.insert(files.end(), itemFiles.begin(), itemFiles.end());
403             }
404         } else {
405             files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
406         }
407     }
408     closedir(dir);
409     return result;
410 }
411 
CheckDestDirTail()412 std::string FilePath::CheckDestDirTail()
413 {
414     if (path_.substr(path_.size()-ZIP_SIZE, ZIP_SIZE) == ZIP) {
415         return path_;
416     } else {
417         return path_ + ZIP;
418     }
419 }
420 }  // namespace LIBZIP
421 }  // namespace AppExecFwk
422 }  // namespace OHOS
423