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