1 /*
2 * Copyright (c) 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 <cstring>
17 #include <dirent.h>
18 #include <iostream>
19 #include <memory>
20 #include <sstream>
21 #include <string_view>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include "filemgmt_libn.h"
26 #include "hilog_wrapper.h"
27
28 namespace OHOS::FileManagement {
29
30 using namespace FileManagement::LibN;
31 using namespace std;
32
33 constexpr int DIR_DEFAULT_PERM = 0770;
34 constexpr int FILTER_MATCH = 1;
35 constexpr int FILTER_DISMATCH = 0;
36 constexpr int MODE_FORCE_MOVE = 0;
37 constexpr uint64_t TIME_CONVERT_BASE = 1000000000;
38 constexpr int SECOND_TO_MILLISECOND = 1000;
39
40 struct NameListArg {
41 struct dirent** namelist = { nullptr };
42 int direntNum = 0;
43 };
44
45 struct StatEntity {
46 uv_stat_t stat_;
47 };
48
Deleter(struct NameListArg * arg)49 static void Deleter(struct NameListArg *arg)
50 {
51 if (arg == nullptr) {
52 HILOG_ERROR("invalid argument");
53 return;
54 }
55 if (arg->namelist == nullptr) {
56 HILOG_ERROR("arg->namelist is nullptr");
57 return;
58 }
59 for (int32_t i = 0; i < arg->direntNum; i++) {
60 free((arg->namelist)[i]);
61 (arg->namelist)[i] = nullptr;
62 }
63 free(arg->namelist);
64 delete arg;
65 arg = nullptr;
66 }
67
FilterFunc(const struct dirent * filename)68 static int32_t FilterFunc(const struct dirent *filename)
69 {
70 if (filename == nullptr) {
71 return FILTER_DISMATCH;
72 }
73 if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") {
74 return FILTER_DISMATCH;
75 }
76 return FILTER_MATCH;
77 }
78
fs_req_cleanup(uv_fs_t * req)79 static void fs_req_cleanup(uv_fs_t* req)
80 {
81 uv_fs_req_cleanup(req);
82 if (req) {
83 delete req;
84 req = nullptr;
85 }
86 }
87
CheckFsStatByPath(const string & path,uv_fs_t * req)88 static int CheckFsStatByPath(const string &path, uv_fs_t* req)
89 {
90 int ret = uv_fs_stat(nullptr, req, path.c_str(), nullptr);
91 if (ret < 0) {
92 HILOG_ERROR("Failed to stat file with path");
93 return ret;
94 }
95 return ERRNO_NOERR;
96 }
97
GetStat(const string & path,StatEntity & statEntity)98 static bool GetStat(const string &path, StatEntity &statEntity)
99 {
100 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> stat_req = {
101 new (nothrow) uv_fs_t, fs_req_cleanup };
102 if (!stat_req) {
103 HILOG_ERROR("Failed to request heap memory.");
104 return false;
105 }
106 auto err = CheckFsStatByPath(path, stat_req.get());
107 if (!err) {
108 statEntity = StatEntity { stat_req->statbuf };
109 return true;
110 }
111 return false;
112 }
113
CheckDir(const string & path)114 static bool CheckDir(const string &path)
115 {
116 struct stat fileInformation;
117 if (stat(path.c_str(), &fileInformation) == 0 && (fileInformation.st_mode & S_IFDIR)) {
118 return true;
119 } else {
120 HILOG_ERROR("Failed to stat file");
121 }
122 return false;
123 }
124
Access(const string & path)125 static tuple<bool, int> Access(const string &path)
126 {
127 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> access_req = { new uv_fs_t, fs_req_cleanup };
128 if (!access_req) {
129 HILOG_ERROR("Failed to request heap memory.");
130 return {false, ENOMEM};
131 }
132 int ret = uv_fs_access(nullptr, access_req.get(), path.c_str(), 0, nullptr);
133 if (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) {
134 HILOG_ERROR("Failed to access file by path");
135 return {false, ret};
136 }
137 bool isExist = (ret == 0);
138 return {isExist, ERRNO_NOERR};
139 }
140
Mkdir(const string & path)141 static bool Mkdir(const string &path)
142 {
143 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> mkdir_req = { new uv_fs_t, fs_req_cleanup };
144 if (!mkdir_req) {
145 HILOG_ERROR("Failed to request heap memory.");
146 return false;
147 }
148 int ret = uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr);
149 if (ret < 0) {
150 HILOG_ERROR("Failed to create directory");
151 return false;
152 }
153 if (ret == 0) {
154 return true;
155 }
156 return false;
157 }
158
CopyAndDeleteFile(const string & src,const string & dest)159 static int CopyAndDeleteFile(const string &src, const string &dest)
160 {
161 // 获取源文件时间
162 StatEntity statEntity;
163 if (!GetStat(src, statEntity)) {
164 HILOG_ERROR("Failed to get file stat.");
165 return EINVAL;
166 }
167 // 拼接秒数和纳秒数
168 uint64_t acTimeLong = static_cast<uint64_t>(statEntity.stat_.st_atim.tv_sec * TIME_CONVERT_BASE +
169 statEntity.stat_.st_atim.tv_nsec);
170 uint64_t modTimeLong = static_cast<uint64_t>(statEntity.stat_.st_mtim.tv_sec * TIME_CONVERT_BASE +
171 statEntity.stat_.st_mtim.tv_nsec);
172 double acTime = static_cast<long double>(acTimeLong) / TIME_CONVERT_BASE;
173 double modTime = static_cast<long double>(modTimeLong) / TIME_CONVERT_BASE;
174
175 int ret = 0;
176 uv_fs_t copyfile_req;
177 ret = uv_fs_copyfile(nullptr, ©file_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr);
178 uv_fs_req_cleanup(©file_req);
179
180 // 设置目标文件时间
181 uv_fs_t utime_req;
182 uv_fs_utime(nullptr, &utime_req, dest.c_str(), acTime, modTime, nullptr);
183 uv_fs_req_cleanup(&utime_req);
184
185 if (ret < 0) {
186 HILOG_ERROR("Failed to move file using copyfile interface.");
187 return ret;
188 }
189 uv_fs_t unlink_req;
190 ret = uv_fs_unlink(nullptr, &unlink_req, src.c_str(), nullptr);
191 if (ret < 0) {
192 HILOG_ERROR("Failed to unlink src file");
193 ret = uv_fs_unlink(nullptr, &unlink_req, dest.c_str(), nullptr);
194 if (ret < 0) {
195 HILOG_ERROR("Failed to unlink dest file");
196 }
197 uv_fs_req_cleanup(&unlink_req);
198 return ret;
199 }
200 uv_fs_req_cleanup(&unlink_req);
201 return ERRNO_NOERR;
202 }
203
RenameFile(const string & src,const string & dest)204 static int RenameFile(const string &src, const string &dest)
205 {
206 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> rename_req = {
207 new uv_fs_t, fs_req_cleanup };
208 if (!rename_req) {
209 HILOG_ERROR("RenameFile: Failed to request heap memory.");
210 return ENOMEM;
211 }
212 int ret = uv_fs_rename(nullptr, rename_req.get(), src.c_str(), dest.c_str(), nullptr);
213 if (ret < 0 && (string_view(uv_err_name(ret)) == "EXDEV")) {
214 HILOG_DEBUG("RenameFile: using CopyAndDeleteFile.");
215 return CopyAndDeleteFile(src, dest);
216 }
217 if (ret < 0) {
218 HILOG_ERROR("RenameFile: Failed to move file using rename syscall ret %{public}d ", ret);
219 return ret;
220 }
221 return ERRNO_NOERR;
222 }
223
RmDirent(const string & fpath)224 static NError RmDirent(const string &fpath)
225 {
226 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> scandir_req = {
227 new (nothrow) uv_fs_t, fs_req_cleanup };
228 if (!scandir_req) {
229 HILOG_ERROR("Failed to request heap memory.");
230 return NError(ENOMEM);
231 }
232 int ret = 0;
233 ret = uv_fs_scandir(nullptr, scandir_req.get(), fpath.c_str(), 0, nullptr);
234 if (ret < 0) {
235 HILOG_ERROR("Failed to scandir, ret: %{public}d", ret);
236 return NError(ret);
237 }
238 uv_dirent_t dent;
239 while (uv_fs_scandir_next(scandir_req.get(), &dent) != UV_EOF) {
240 string filePath = fpath + "/" + string(dent.name);
241 if (dent.type == UV_DIRENT_FILE) {
242 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> unlink_req = {
243 new (nothrow) uv_fs_t, fs_req_cleanup };
244 if (!unlink_req) {
245 HILOG_ERROR("Failed to request heap memory.");
246 return NError(ENOMEM);
247 }
248 ret = uv_fs_unlink(nullptr, unlink_req.get(), filePath.c_str(), nullptr);
249 if (ret < 0) {
250 HILOG_ERROR("Failed to unlink file, ret: %{public}d", ret);
251 return NError(ret);
252 }
253 } else if (dent.type == UV_DIRENT_DIR) {
254 auto rmDirentRes = RmDirent(filePath);
255 if (rmDirentRes) {
256 return rmDirentRes;
257 }
258 }
259 }
260 unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> rmdir_req = {
261 new (nothrow) uv_fs_t, fs_req_cleanup };
262 if (!rmdir_req) {
263 HILOG_ERROR("Failed to request heap memory.");
264 return NError(ENOMEM);
265 }
266 ret = uv_fs_rmdir(nullptr, rmdir_req.get(), fpath.c_str(), nullptr);
267 if (ret < 0) {
268 HILOG_ERROR("Failed to rmdir empty dir, ret: %{public}d", ret);
269 return NError(ret);
270 }
271 return NError(ERRNO_NOERR);
272 }
273
ScanDir(const string & path)274 static int ScanDir(const string &path)
275 {
276 unique_ptr<struct NameListArg, decltype(Deleter)*> pNameList = { new (nothrow) struct NameListArg, Deleter };
277 if (!pNameList) {
278 HILOG_ERROR("Failed to request heap memory.");
279 return ENOMEM;
280 }
281 HILOG_INFO("RecursiveFunc: scandir path = %{private}s", path.c_str());
282 return scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort);
283 }
284 } // OHOS::FileManagement