1 /*
2 * Copyright (c) 2024 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 "res_sched_file_util.h"
17
18 #include <system_error>
19 #include <cstring>
20 #include <dirent.h>
21 #include <fstream>
22 #include <filesystem>
23 #include <sys/statfs.h>
24
25 #include "config_policy_utils.h"
26 #include "directory_ex.h"
27 #include "file_ex.h"
28 #include "res_sched_log.h"
29
30 namespace OHOS {
31 namespace ResourceSchedule {
32 namespace ResCommonUtil {
WriteFileReclaim(int32_t pid)33 void WriteFileReclaim(int32_t pid)
34 {
35 std::string path = "/proc/" + std::to_string(pid) + "/reclaim";
36 std::string contentStr = "1";
37 int fd = open(path.c_str(), O_WRONLY);
38 // judge whether open failed
39 if (fd < 0) {
40 RESSCHED_LOGE("%{public}s: open failed.", __func__);
41 return;
42 }
43 // write content to fd
44 write(fd, contentStr.c_str(), contentStr.length());
45 close(fd);
46 }
47
GetRealPath(const std::string & filePath,std::string & realPath)48 bool GetRealPath(const std::string& filePath, std::string& realPath)
49 {
50 if (!OHOS::PathToRealPath(filePath, realPath)) {
51 RESSCHED_LOGE("%{public}s: get real path failed.", __func__);
52 return false;
53 }
54 return true;
55 }
56
PathOrFileExists(const std::string & path)57 bool PathOrFileExists(const std::string& path)
58 {
59 if (access(path.c_str(), F_OK) != 0) {
60 RESSCHED_LOGE("%{public}s: access failed.", __func__);
61 return false;
62 }
63 return true;
64 }
65
DirIterator(const std::string & filePath,std::vector<std::string> & iters)66 bool DirIterator(const std::string& filePath, std::vector<std::string>& iters)
67 {
68 DIR *dir = opendir(filePath.c_str());
69 // input invaild, open failed
70 if (dir == nullptr) {
71 RESSCHED_LOGE("%{public}s: open failed.", __func__);
72 return false;
73 }
74 struct dirent *ptr;
75 while ((ptr = readdir(dir)) != nullptr) {
76 // current dir is path of '.' or '..'
77 if ((strcmp(ptr->d_name, ".") == 0) || (strcmp(ptr->d_name, "..") == 0)) {
78 RESSCHED_LOGD("%{public}s: skip current and pre path", __func__);
79 continue;
80 }
81 iters.emplace_back(IncludeTrailingPathDelimiter(filePath) + std::string(ptr->d_name));
82 }
83 closedir(dir);
84 return true;
85 }
86
IsEmptyDir(const std::string & filePath)87 bool IsEmptyDir(const std::string& filePath)
88 {
89 return OHOS::IsEmptyFolder(filePath);
90 }
91
IsDir(const std::string & filePath)92 bool IsDir(const std::string& filePath)
93 {
94 struct stat info{};
95 // dose not exist
96 if (stat(filePath.c_str(), &info) != 0) {
97 RESSCHED_LOGE("%{public}s: file path not exist.", __func__);
98 return false;
99 }
100 // is not directory
101 if (!(info.st_mode & S_IFDIR)) {
102 return false;
103 }
104 return true;
105 }
106
CreateDir(const std::string & dir,const mode_t & mode)107 bool CreateDir(const std::string& dir, const mode_t& mode)
108 {
109 // create directory
110 if (!OHOS::ForceCreateDirectory(dir)) {
111 RESSCHED_LOGE("%{public}s: Failed to create dir", __func__);
112 return false;
113 }
114 // change directory's mode.
115 if (!OHOS::ChangeModeDirectory(dir, mode)) {
116 RESSCHED_LOGE("%{public}s: Failed to change dir mode to %{public}ud", __func__,
117 mode);
118 // if change failed, remove it.
119 RemoveDirs(dir);
120 return false;
121 }
122 return true;
123 }
124
CreateFile(const std::string & filePath,const mode_t & mode)125 bool CreateFile(const std::string& filePath, const mode_t& mode)
126 {
127 std::ofstream fd;
128 // create and open file.
129 fd.open(filePath);
130 if (!fd.is_open()) {
131 //create filed
132 RESSCHED_LOGE("%{public}s: Failed to create file", __func__);
133 return false;
134 }
135 fd.close();
136
137 //change file mode
138 if (!OHOS::ChangeModeFile(filePath, mode)) {
139 //change failed
140 RESSCHED_LOGE("%{public}s: Failed to change file mode to %{public}ud", __func__,
141 mode);
142 RemoveFile(filePath);
143 return false;
144 }
145 return true;
146 }
147
RemoveDirs(const std::string & dir)148 bool RemoveDirs(const std::string& dir)
149 {
150 if (!OHOS::ForceRemoveDirectory(dir)) {
151 RESSCHED_LOGE("%{public}s: Failed to remove dir", __func__);
152 return false;
153 }
154 return true;
155 }
156
RemoveFile(const std::string & filePath)157 bool RemoveFile(const std::string& filePath)
158 {
159 if (!OHOS::RemoveFile(filePath)) {
160 RESSCHED_LOGE("%{public}s: Failed to remove file", __func__);
161 return false;
162 }
163 return true;
164 }
165
ExtractFileName(const std::string & filePath)166 std::string ExtractFileName(const std::string& filePath)
167 {
168 return OHOS::ExtractFileName(filePath);
169 }
170
IsBLKPath(const std::string & filePath)171 bool IsBLKPath(const std::string& filePath)
172 {
173 struct stat sb;
174 if (stat(filePath.c_str(), &sb) == 0 && S_ISBLK(sb.st_mode)) {
175 return true;
176 }
177 return false;
178 }
179
SaveStringToFile(const std::string & filePath,const std::string & content,bool truncated)180 bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated)
181 {
182 return OHOS::SaveStringToFile(filePath, content, truncated);
183 }
184
ReadLinesFromFile(const std::string & filePath,std::vector<std::string> & lines)185 bool ReadLinesFromFile(const std::string& filePath, std::vector<std::string>& lines)
186 {
187 std::string line;
188 char tmpPath[PATH_MAX + 1] = {0};
189 auto len = filePath.length();
190 if (len == 0 || len > PATH_MAX || !realpath(filePath.c_str(), tmpPath)) {
191 RESSCHED_LOGE("%{public}s: file path invalid", __func__);
192 return false;
193 }
194 std::string realConfigPath(tmpPath);
195 std::ifstream fin(realConfigPath, std::ifstream::in);
196 // judge whether open failed.
197 if (!fin) {
198 RESSCHED_LOGE("%{public}s: open file failed.", __func__);
199 return false;
200 }
201 // clear container and read lines
202 lines.clear();
203 while (fin.peek() != EOF) {
204 getline(fin, line);
205 lines.emplace_back(line);
206 }
207 fin.close();
208 return true;
209 }
210
DoCopy(const std::string & src,const std::string & des)211 bool DoCopy(const std::string& src, const std::string& des)
212 {
213 std::filesystem::path sPath(src);
214 std::filesystem::path dPath(des);
215 std::error_code errNo;
216
217 const auto copyOptions = std::filesystem::copy_options::overwrite_existing |
218 std::filesystem::copy_options::recursive |
219 std::filesystem::copy_options::skip_symlinks;
220 std::filesystem::copy(sPath, dPath, copyOptions, errNo);
221 // if has some error in copy, record errno
222 if (errNo.value()) {
223 RESSCHED_LOGE("copy failed errno:%{public}d", errNo.value());
224 return false;
225 }
226 RESSCHED_LOGD("copy success");
227 return true;
228 }
229
CopyFile(const std::string & src,const std::string & des)230 bool CopyFile(const std::string& src, const std::string& des)
231 {
232 // judge src exist.
233 if (!PathOrFileExists(src)) {
234 RESSCHED_LOGE("%{public}s: src path invalid!", __func__);
235 return false;
236 }
237 if (PathOrFileExists(des)) {
238 // target path is exist, remove it before copy.
239 if (!RemoveDirs(des)) {
240 RESSCHED_LOGE("%{public}s: target path is exist and remove failed!", __func__);
241 return false;
242 }
243 }
244 errno = 0;
245 // create target directory.
246 if (mkdir(des.c_str(), S_IRWXU) != 0 && errno != EEXIST) {
247 RESSCHED_LOGE("%{public}s: create target path failed!", __func__);
248 return false;
249 }
250 // do real copy action.
251 return DoCopy(src, des);
252 }
253
GetRealConfigPath(const std::string & configPath,std::string & realConfigPath)254 bool GetRealConfigPath(const std::string& configPath, std::string& realConfigPath)
255 {
256 // judge input path vaild.
257 if (configPath.empty()) {
258 RESSCHED_LOGE("%{public}s:the input config path is empty", __func__);
259 return false;
260 }
261 char buf[PATH_MAX];
262 char* tmpPath = GetOneCfgFile(configPath.c_str(), buf, PATH_MAX);
263 char absolutePath[PATH_MAX] = {0};
264 // if config path is vaild, obtain real path.
265 if (!tmpPath || strlen(tmpPath) > PATH_MAX || !realpath(tmpPath, absolutePath)) {
266 RESSCHED_LOGE("%{public}s:get one config file failed", __func__);
267 return false;
268 }
269 realConfigPath = std::string(absolutePath);
270 return true;
271 }
272
IsValidPath(const std::string & path)273 bool IsValidPath(const std::string& path)
274 {
275 return !(path.empty() || path.find('\0') != std::string::npos);
276 }
277
GetFileSize(const std::string & path)278 uint64_t GetFileSize(const std::string& path)
279 {
280 struct stat st;
281 return stat(path.c_str(), &st) ? 0 : static_cast<uint64_t>(st.st_size);
282 }
283
GetPartitionName(const std::string & path)284 std::string GetPartitionName(const std::string& path)
285 {
286 std::string partition;
287 std::size_t first = path.find_first_of("/");
288 if (first == std::string::npos) {
289 partition = "/" + path;
290 return partition;
291 }
292 std::size_t second = path.find_first_of("/", first + 1);
293 if (second == std::string::npos) {
294 if (path.at(0) != '/') {
295 partition = "/" + path.substr(0, first);
296 } else {
297 partition = path;
298 }
299 return partition;
300 }
301 partition = path.substr(0, second - first);
302 return partition;
303 }
304
GetDeviceVailidSize(const std::string & path)305 double GetDeviceVailidSize(const std::string& path)
306 {
307 std::string partitionName = GetPartitionName(path);
308 struct statfs stat;
309 if (statfs(partitionName.c_str(), &stat) != 0) {
310 return 0;
311 }
312 constexpr double units = 1024.0;
313 return (static_cast<double>(stat.f_bfree) / units) * (static_cast<double>(stat.f_bsize) / units);
314 }
315 } // namespace ResCommonUtil
316 } // namespace ResourceSchedule
317 } // namespace OHOS
318