• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &copyfile_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr);
179     uv_fs_req_cleanup(&copyfile_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