• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 
16 #include "b_filesystem/b_dir.h"
17 
18 #include <algorithm>
19 #include <dirent.h>
20 #include <fnmatch.h>
21 #include <functional>
22 #include <glob.h>
23 #include <memory>
24 #include <set>
25 #include <string>
26 #include <tuple>
27 #include <vector>
28 
29 #include "b_error/b_error.h"
30 #include "b_resources/b_constants.h"
31 #include "directory_ex.h"
32 #include "errors.h"
33 #include "filemgmt_libhilog.h"
34 
35 namespace OHOS::FileManagement::Backup {
36 using namespace std;
37 
GetDirFilesDetail(const string & path,bool recursion,off_t size=-1)38 pair<ErrCode, map<string, struct stat>> GetDirFilesDetail(const string &path, bool recursion, off_t size = -1)
39 {
40     map<string, struct stat> files;
41     unique_ptr<DIR, function<void(DIR *)>> dir = {opendir(path.c_str()), closedir};
42     if (!dir) {
43         HILOGE("Invalid directory path: %{private}s", path.c_str());
44         return {BError(errno).GetCode(), files};
45     }
46 
47     struct dirent *ptr = nullptr;
48     while (!!(ptr = readdir(dir.get()))) {
49         // current dir OR parent dir
50         if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
51             continue;
52         } else if (ptr->d_type == DT_DIR) {
53             if (!recursion) {
54                 continue;
55             }
56 
57             auto [errCode, subfiles] =
58                 GetDirFilesDetail(IncludeTrailingPathDelimiter(path) + string(ptr->d_name), recursion, size);
59             if (errCode != 0) {
60                 return {errCode, files};
61             }
62             files.merge(subfiles);
63         } else if (ptr->d_type == DT_LNK) {
64             continue;
65         } else {
66             struct stat sta = {};
67             string fileName = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
68             if (stat(fileName.data(), &sta) == -1) {
69                 continue;
70             }
71             if (sta.st_size < size) {
72                 continue;
73             }
74             HILOGI("Find big file");
75             files.try_emplace(fileName, sta);
76         }
77     }
78 
79     return {BError(BError::Codes::OK).GetCode(), files};
80 }
81 
GetDirFiles(const string & path)82 tuple<ErrCode, vector<string>> BDir::GetDirFiles(const string &path)
83 {
84     vector<string> files;
85     unique_ptr<DIR, function<void(DIR *)>> dir = {opendir(path.c_str()), closedir};
86     if (!dir) {
87         HILOGE("Invalid directory path: %{private}s", path.c_str());
88         return {BError(errno).GetCode(), files};
89     }
90 
91     struct dirent *ptr = nullptr;
92     while (!!(ptr = readdir(dir.get()))) {
93         // current dir OR parent dir
94         if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
95             continue;
96         } else if (ptr->d_type == DT_DIR) {
97             continue;
98         } else {
99             files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
100         }
101     }
102 
103     return {BError(BError::Codes::OK).GetCode(), files};
104 }
105 
ExpandPathWildcard(const vector<string> & vec)106 static set<string> ExpandPathWildcard(const vector<string> &vec)
107 {
108     unique_ptr<glob_t, function<void(glob_t *)>> gl {new glob_t, [](glob_t *ptr) { globfree(ptr); }};
109     *gl = {};
110 
111     int flags = GLOB_DOOFFS | GLOB_MARK;
112     for (const string &pattern : vec) {
113         if (!pattern.empty()) {
114             glob(pattern.data(), flags, NULL, gl.get());
115             flags |= GLOB_APPEND;
116         }
117     }
118 
119     set<string> expandPath, filteredPath;
120     for (size_t i = 0; i < gl->gl_pathc; ++i) {
121         expandPath.emplace(gl->gl_pathv[i]);
122     }
123 
124     for (auto it = expandPath.begin(); it != expandPath.end(); ++it) {
125         filteredPath.insert(*it);
126         if (*it->rbegin() != '/') {
127             continue;
128         }
129         auto jt = it;
130         for (++jt; jt != expandPath.end() && (jt->find(*it) == 0); ++jt) {
131         }
132 
133         it = --jt;
134     }
135 
136     return filteredPath;
137 }
138 
GetBigFiles(const vector<string> & includes,const vector<string> & excludes)139 pair<ErrCode, map<string, struct stat>> BDir::GetBigFiles(const vector<string> &includes,
140                                                           const vector<string> &excludes)
141 {
142     set<string> inc = ExpandPathWildcard(includes);
143 
144     map<string, struct stat> incFiles;
145     for (const auto &item : inc) {
146         auto [errCode, files] =
147             OHOS::FileManagement::Backup::GetDirFilesDetail(item, true, BConstants::BIG_FILE_BOUNDARY);
148         if (errCode == 0) {
149             int32_t num = static_cast<int32_t>(files.size());
150             HILOGI("found big files. total number is : %{public}d", num);
151             incFiles.merge(move(files));
152         }
153     }
154 
155     auto isMatch = [](const vector<string> &s, const string &str) -> bool {
156         if (str.empty()) {
157             return false;
158         }
159         for (const string &item : s) {
160             if (!item.empty() && (fnmatch(item.data(), str.data(), FNM_LEADING_DIR) == 0)) {
161                 HILOGI("file %{public}s matchs exclude condition", str.c_str());
162                 return true;
163             }
164         }
165         return false;
166     };
167 
168     map<string, struct stat> bigFiles;
169     for (const auto &item : incFiles) {
170         if (!isMatch(excludes, item.first)) {
171             HILOGI("file %{public}s matchs include condition and unmatchs exclude condition", item.first.c_str());
172             bigFiles[item.first] = item.second;
173         }
174     }
175     int32_t num = static_cast<int32_t>(bigFiles.size());
176     HILOGI("total number of big files is %{public}d", num);
177     return {ERR_OK, move(bigFiles)};
178 }
179 
GetDirs(const vector<string_view> & paths)180 vector<string> BDir::GetDirs(const vector<string_view> &paths)
181 {
182     vector<string> wildcardPath(paths.begin(), paths.end());
183     set<string> inc = ExpandPathWildcard(wildcardPath);
184     vector<string> dirs(inc.begin(), inc.end());
185     return dirs;
186 }
187 } // namespace OHOS::FileManagement::Backup