• 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;
120     set<string> filteredPath;
121     for (size_t i = 0; i < gl->gl_pathc; ++i) {
122         expandPath.emplace(gl->gl_pathv[i]);
123     }
124 
125     for (auto it = expandPath.begin(); it != expandPath.end(); ++it) {
126         filteredPath.insert(*it);
127         if (*it->rbegin() != '/') {
128             continue;
129         }
130         auto jt = it;
131         for (++jt; jt != expandPath.end() && (jt->find(*it) == 0); ++jt) {
132         }
133 
134         it = --jt;
135     }
136 
137     return filteredPath;
138 }
139 
GetBigFiles(const vector<string> & includes,const vector<string> & excludes)140 pair<ErrCode, map<string, struct stat>> BDir::GetBigFiles(const vector<string> &includes,
141                                                           const vector<string> &excludes)
142 {
143     set<string> inc = ExpandPathWildcard(includes);
144 
145     map<string, struct stat> incFiles;
146     for (const auto &item : inc) {
147         auto [errCode, files] =
148             OHOS::FileManagement::Backup::GetDirFilesDetail(item, true, BConstants::BIG_FILE_BOUNDARY);
149         if (errCode == 0) {
150             int32_t num = static_cast<int32_t>(files.size());
151             HILOGI("found big files. total number is : %{public}d", num);
152             incFiles.merge(move(files));
153         }
154     }
155 
156     auto isMatch = [](const vector<string> &s, const string &str) -> bool {
157         if (str.empty()) {
158             return false;
159         }
160         for (const string &item : s) {
161             if (!item.empty() && (fnmatch(item.data(), str.data(), FNM_LEADING_DIR) == 0)) {
162                 HILOGI("file %{public}s matchs exclude condition", str.c_str());
163                 return true;
164             }
165         }
166         return false;
167     };
168 
169     map<string, struct stat> bigFiles;
170     for (const auto &item : incFiles) {
171         if (!isMatch(excludes, item.first)) {
172             HILOGI("file %{public}s matchs include condition and unmatchs exclude condition", item.first.c_str());
173             bigFiles[item.first] = item.second;
174         }
175     }
176     int32_t num = static_cast<int32_t>(bigFiles.size());
177     HILOGI("total number of big files is %{public}d", num);
178     return {ERR_OK, move(bigFiles)};
179 }
180 
GetDirs(const vector<string_view> & paths)181 vector<string> BDir::GetDirs(const vector<string_view> &paths)
182 {
183     vector<string> wildcardPath(paths.begin(), paths.end());
184     set<string> inc = ExpandPathWildcard(wildcardPath);
185     vector<string> dirs(inc.begin(), inc.end());
186     return dirs;
187 }
188 } // namespace OHOS::FileManagement::Backup