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