• 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_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