18d05d8e7Sopenharmony_ci/* 28d05d8e7Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 38d05d8e7Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48d05d8e7Sopenharmony_ci * you may not use this file except in compliance with the License. 58d05d8e7Sopenharmony_ci * You may obtain a copy of the License at 68d05d8e7Sopenharmony_ci * 78d05d8e7Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88d05d8e7Sopenharmony_ci * 98d05d8e7Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108d05d8e7Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118d05d8e7Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128d05d8e7Sopenharmony_ci * See the License for the specific language governing permissions and 138d05d8e7Sopenharmony_ci * limitations under the License. 148d05d8e7Sopenharmony_ci */ 158d05d8e7Sopenharmony_ci 168d05d8e7Sopenharmony_ci#include <cstring> 178d05d8e7Sopenharmony_ci#include <dirent.h> 188d05d8e7Sopenharmony_ci#include <iostream> 198d05d8e7Sopenharmony_ci#include <memory> 208d05d8e7Sopenharmony_ci#include <sstream> 218d05d8e7Sopenharmony_ci#include <string_view> 228d05d8e7Sopenharmony_ci#include <sys/stat.h> 238d05d8e7Sopenharmony_ci#include <unistd.h> 248d05d8e7Sopenharmony_ci 258d05d8e7Sopenharmony_ci#include "filemgmt_libn.h" 268d05d8e7Sopenharmony_ci#include "hilog_wrapper.h" 278d05d8e7Sopenharmony_ci 288d05d8e7Sopenharmony_cinamespace OHOS::FileManagement { 298d05d8e7Sopenharmony_ci 308d05d8e7Sopenharmony_ciusing namespace FileManagement::LibN; 318d05d8e7Sopenharmony_ciusing namespace std; 328d05d8e7Sopenharmony_ci 338d05d8e7Sopenharmony_ciconstexpr int DIR_DEFAULT_PERM = 0770; 348d05d8e7Sopenharmony_ciconstexpr int FILTER_MATCH = 1; 358d05d8e7Sopenharmony_ciconstexpr int FILTER_DISMATCH = 0; 368d05d8e7Sopenharmony_ciconstexpr int MODE_FORCE_MOVE = 0; 378d05d8e7Sopenharmony_ciconstexpr uint64_t TIME_CONVERT_BASE = 1000000000; 388d05d8e7Sopenharmony_ciconstexpr int SECOND_TO_MILLISECOND = 1000; 398d05d8e7Sopenharmony_ci 408d05d8e7Sopenharmony_cistruct NameListArg { 418d05d8e7Sopenharmony_ci struct dirent** namelist = { nullptr }; 428d05d8e7Sopenharmony_ci int direntNum = 0; 438d05d8e7Sopenharmony_ci}; 448d05d8e7Sopenharmony_ci 458d05d8e7Sopenharmony_cistruct StatEntity { 468d05d8e7Sopenharmony_ci uv_stat_t stat_; 478d05d8e7Sopenharmony_ci}; 488d05d8e7Sopenharmony_ci 498d05d8e7Sopenharmony_cistatic void Deleter(struct NameListArg *arg) 508d05d8e7Sopenharmony_ci{ 518d05d8e7Sopenharmony_ci if (arg == nullptr) { 528d05d8e7Sopenharmony_ci HILOG_ERROR("invalid argument"); 538d05d8e7Sopenharmony_ci return; 548d05d8e7Sopenharmony_ci } 558d05d8e7Sopenharmony_ci for (int i = 0; i < arg->direntNum; i++) { 568d05d8e7Sopenharmony_ci free((arg->namelist)[i]); 578d05d8e7Sopenharmony_ci (arg->namelist)[i] = nullptr; 588d05d8e7Sopenharmony_ci } 598d05d8e7Sopenharmony_ci free(arg->namelist); 608d05d8e7Sopenharmony_ci delete arg; 618d05d8e7Sopenharmony_ci arg = nullptr; 628d05d8e7Sopenharmony_ci} 638d05d8e7Sopenharmony_ci 648d05d8e7Sopenharmony_cistatic int32_t FilterFunc(const struct dirent *filename) 658d05d8e7Sopenharmony_ci{ 668d05d8e7Sopenharmony_ci if (filename == nullptr) { 678d05d8e7Sopenharmony_ci return FILTER_DISMATCH; 688d05d8e7Sopenharmony_ci } 698d05d8e7Sopenharmony_ci if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") { 708d05d8e7Sopenharmony_ci return FILTER_DISMATCH; 718d05d8e7Sopenharmony_ci } 728d05d8e7Sopenharmony_ci return FILTER_MATCH; 738d05d8e7Sopenharmony_ci} 748d05d8e7Sopenharmony_ci 758d05d8e7Sopenharmony_cistatic void fs_req_cleanup(uv_fs_t* req) 768d05d8e7Sopenharmony_ci{ 778d05d8e7Sopenharmony_ci uv_fs_req_cleanup(req); 788d05d8e7Sopenharmony_ci if (req) { 798d05d8e7Sopenharmony_ci delete req; 808d05d8e7Sopenharmony_ci req = nullptr; 818d05d8e7Sopenharmony_ci } 828d05d8e7Sopenharmony_ci} 838d05d8e7Sopenharmony_ci 848d05d8e7Sopenharmony_cistatic int CheckFsStatByPath(const string &path, uv_fs_t* req) 858d05d8e7Sopenharmony_ci{ 868d05d8e7Sopenharmony_ci int ret = uv_fs_stat(nullptr, req, path.c_str(), nullptr); 878d05d8e7Sopenharmony_ci if (ret < 0) { 888d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to stat file with path"); 898d05d8e7Sopenharmony_ci return ret; 908d05d8e7Sopenharmony_ci } 918d05d8e7Sopenharmony_ci return ERRNO_NOERR; 928d05d8e7Sopenharmony_ci} 938d05d8e7Sopenharmony_ci 948d05d8e7Sopenharmony_cistatic bool GetStat(const string &path, StatEntity &statEntity) 958d05d8e7Sopenharmony_ci{ 968d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> stat_req = { 978d05d8e7Sopenharmony_ci new (nothrow) uv_fs_t, fs_req_cleanup }; 988d05d8e7Sopenharmony_ci if (!stat_req) { 998d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 1008d05d8e7Sopenharmony_ci return false; 1018d05d8e7Sopenharmony_ci } 1028d05d8e7Sopenharmony_ci auto err = CheckFsStatByPath(path, stat_req.get()); 1038d05d8e7Sopenharmony_ci if (!err) { 1048d05d8e7Sopenharmony_ci statEntity = StatEntity { stat_req->statbuf }; 1058d05d8e7Sopenharmony_ci return true; 1068d05d8e7Sopenharmony_ci } 1078d05d8e7Sopenharmony_ci return false; 1088d05d8e7Sopenharmony_ci} 1098d05d8e7Sopenharmony_ci 1108d05d8e7Sopenharmony_cistatic bool CheckDir(const string &path) 1118d05d8e7Sopenharmony_ci{ 1128d05d8e7Sopenharmony_ci struct stat fileInformation; 1138d05d8e7Sopenharmony_ci if (stat(path.c_str(), &fileInformation) == 0 && (fileInformation.st_mode & S_IFDIR)) { 1148d05d8e7Sopenharmony_ci return true; 1158d05d8e7Sopenharmony_ci } else { 1168d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to stat file"); 1178d05d8e7Sopenharmony_ci } 1188d05d8e7Sopenharmony_ci return false; 1198d05d8e7Sopenharmony_ci} 1208d05d8e7Sopenharmony_ci 1218d05d8e7Sopenharmony_cistatic tuple<bool, int> Access(const string &path) 1228d05d8e7Sopenharmony_ci{ 1238d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> access_req = { new uv_fs_t, fs_req_cleanup }; 1248d05d8e7Sopenharmony_ci if (!access_req) { 1258d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 1268d05d8e7Sopenharmony_ci return {false, ENOMEM}; 1278d05d8e7Sopenharmony_ci } 1288d05d8e7Sopenharmony_ci int ret = uv_fs_access(nullptr, access_req.get(), path.c_str(), 0, nullptr); 1298d05d8e7Sopenharmony_ci if (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) { 1308d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to access file by path"); 1318d05d8e7Sopenharmony_ci return {false, ret}; 1328d05d8e7Sopenharmony_ci } 1338d05d8e7Sopenharmony_ci bool isExist = (ret == 0); 1348d05d8e7Sopenharmony_ci return {isExist, ERRNO_NOERR}; 1358d05d8e7Sopenharmony_ci} 1368d05d8e7Sopenharmony_ci 1378d05d8e7Sopenharmony_cistatic bool Mkdir(const string &path) 1388d05d8e7Sopenharmony_ci{ 1398d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> mkdir_req = { new uv_fs_t, fs_req_cleanup }; 1408d05d8e7Sopenharmony_ci if (!mkdir_req) { 1418d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 1428d05d8e7Sopenharmony_ci return false; 1438d05d8e7Sopenharmony_ci } 1448d05d8e7Sopenharmony_ci int ret = uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr); 1458d05d8e7Sopenharmony_ci if (ret < 0) { 1468d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to create directory"); 1478d05d8e7Sopenharmony_ci return false; 1488d05d8e7Sopenharmony_ci } 1498d05d8e7Sopenharmony_ci if (ret == 0) { 1508d05d8e7Sopenharmony_ci return true; 1518d05d8e7Sopenharmony_ci } 1528d05d8e7Sopenharmony_ci return false; 1538d05d8e7Sopenharmony_ci} 1548d05d8e7Sopenharmony_ci 1558d05d8e7Sopenharmony_cistatic int CopyAndDeleteFile(const string &src, const string &dest) 1568d05d8e7Sopenharmony_ci{ 1578d05d8e7Sopenharmony_ci // 获取源文件时间 1588d05d8e7Sopenharmony_ci StatEntity statEntity; 1598d05d8e7Sopenharmony_ci if (!GetStat(src, statEntity)) { 1608d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to get file stat."); 1618d05d8e7Sopenharmony_ci return EINVAL; 1628d05d8e7Sopenharmony_ci } 1638d05d8e7Sopenharmony_ci // 拼接秒数和纳秒数 1648d05d8e7Sopenharmony_ci uint64_t acTimeLong = static_cast<uint64_t>(statEntity.stat_.st_atim.tv_sec * TIME_CONVERT_BASE + 1658d05d8e7Sopenharmony_ci statEntity.stat_.st_atim.tv_nsec); 1668d05d8e7Sopenharmony_ci uint64_t modTimeLong = static_cast<uint64_t>(statEntity.stat_.st_mtim.tv_sec * TIME_CONVERT_BASE + 1678d05d8e7Sopenharmony_ci statEntity.stat_.st_mtim.tv_nsec); 1688d05d8e7Sopenharmony_ci double acTime = static_cast<long double>(acTimeLong) / TIME_CONVERT_BASE; 1698d05d8e7Sopenharmony_ci double modTime = static_cast<long double>(modTimeLong) / TIME_CONVERT_BASE; 1708d05d8e7Sopenharmony_ci 1718d05d8e7Sopenharmony_ci int ret = 0; 1728d05d8e7Sopenharmony_ci uv_fs_t copyfile_req; 1738d05d8e7Sopenharmony_ci ret = uv_fs_copyfile(nullptr, ©file_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr); 1748d05d8e7Sopenharmony_ci uv_fs_req_cleanup(©file_req); 1758d05d8e7Sopenharmony_ci 1768d05d8e7Sopenharmony_ci // 设置目标文件时间 1778d05d8e7Sopenharmony_ci uv_fs_t utime_req; 1788d05d8e7Sopenharmony_ci uv_fs_utime(nullptr, &utime_req, dest.c_str(), acTime, modTime, nullptr); 1798d05d8e7Sopenharmony_ci uv_fs_req_cleanup(&utime_req); 1808d05d8e7Sopenharmony_ci 1818d05d8e7Sopenharmony_ci if (ret < 0) { 1828d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to move file using copyfile interface."); 1838d05d8e7Sopenharmony_ci return ret; 1848d05d8e7Sopenharmony_ci } 1858d05d8e7Sopenharmony_ci uv_fs_t unlink_req; 1868d05d8e7Sopenharmony_ci ret = uv_fs_unlink(nullptr, &unlink_req, src.c_str(), nullptr); 1878d05d8e7Sopenharmony_ci if (ret < 0) { 1888d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to unlink src file"); 1898d05d8e7Sopenharmony_ci ret = uv_fs_unlink(nullptr, &unlink_req, dest.c_str(), nullptr); 1908d05d8e7Sopenharmony_ci if (ret < 0) { 1918d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to unlink dest file"); 1928d05d8e7Sopenharmony_ci } 1938d05d8e7Sopenharmony_ci uv_fs_req_cleanup(&unlink_req); 1948d05d8e7Sopenharmony_ci return ret; 1958d05d8e7Sopenharmony_ci } 1968d05d8e7Sopenharmony_ci uv_fs_req_cleanup(&unlink_req); 1978d05d8e7Sopenharmony_ci return ERRNO_NOERR; 1988d05d8e7Sopenharmony_ci} 1998d05d8e7Sopenharmony_ci 2008d05d8e7Sopenharmony_cistatic int RenameFile(const string &src, const string &dest) 2018d05d8e7Sopenharmony_ci{ 2028d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> rename_req = { 2038d05d8e7Sopenharmony_ci new uv_fs_t, fs_req_cleanup }; 2048d05d8e7Sopenharmony_ci if (!rename_req) { 2058d05d8e7Sopenharmony_ci HILOG_ERROR("RenameFile: Failed to request heap memory."); 2068d05d8e7Sopenharmony_ci return false; 2078d05d8e7Sopenharmony_ci } 2088d05d8e7Sopenharmony_ci int ret = uv_fs_rename(nullptr, rename_req.get(), src.c_str(), dest.c_str(), nullptr); 2098d05d8e7Sopenharmony_ci if (ret < 0 && (string_view(uv_err_name(ret)) == "EXDEV")) { 2108d05d8e7Sopenharmony_ci HILOG_DEBUG("RenameFile: using CopyAndDeleteFile."); 2118d05d8e7Sopenharmony_ci return CopyAndDeleteFile(src, dest); 2128d05d8e7Sopenharmony_ci } 2138d05d8e7Sopenharmony_ci if (ret < 0) { 2148d05d8e7Sopenharmony_ci HILOG_ERROR("RenameFile: Failed to move file using rename syscall ret %{public}d ", ret); 2158d05d8e7Sopenharmony_ci return ret; 2168d05d8e7Sopenharmony_ci } 2178d05d8e7Sopenharmony_ci return ERRNO_NOERR; 2188d05d8e7Sopenharmony_ci} 2198d05d8e7Sopenharmony_ci 2208d05d8e7Sopenharmony_cistatic NError RmDirent(const string &fpath) 2218d05d8e7Sopenharmony_ci{ 2228d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> scandir_req = { 2238d05d8e7Sopenharmony_ci new (nothrow) uv_fs_t, fs_req_cleanup }; 2248d05d8e7Sopenharmony_ci if (!scandir_req) { 2258d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 2268d05d8e7Sopenharmony_ci return NError(ENOMEM); 2278d05d8e7Sopenharmony_ci } 2288d05d8e7Sopenharmony_ci int ret = 0; 2298d05d8e7Sopenharmony_ci ret = uv_fs_scandir(nullptr, scandir_req.get(), fpath.c_str(), 0, nullptr); 2308d05d8e7Sopenharmony_ci if (ret < 0) { 2318d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to scandir, ret: %{public}d", ret); 2328d05d8e7Sopenharmony_ci return NError(ret); 2338d05d8e7Sopenharmony_ci } 2348d05d8e7Sopenharmony_ci uv_dirent_t dent; 2358d05d8e7Sopenharmony_ci while (uv_fs_scandir_next(scandir_req.get(), &dent) != UV_EOF) { 2368d05d8e7Sopenharmony_ci string filePath = fpath + "/" + string(dent.name); 2378d05d8e7Sopenharmony_ci if (dent.type == UV_DIRENT_FILE) { 2388d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> unlink_req = { 2398d05d8e7Sopenharmony_ci new (nothrow) uv_fs_t, fs_req_cleanup }; 2408d05d8e7Sopenharmony_ci if (!unlink_req) { 2418d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 2428d05d8e7Sopenharmony_ci return NError(ENOMEM); 2438d05d8e7Sopenharmony_ci } 2448d05d8e7Sopenharmony_ci ret = uv_fs_unlink(nullptr, unlink_req.get(), filePath.c_str(), nullptr); 2458d05d8e7Sopenharmony_ci if (ret < 0) { 2468d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to unlink file, ret: %{public}d", ret); 2478d05d8e7Sopenharmony_ci return NError(ret); 2488d05d8e7Sopenharmony_ci } 2498d05d8e7Sopenharmony_ci } else if (dent.type == UV_DIRENT_DIR) { 2508d05d8e7Sopenharmony_ci auto rmDirentRes = RmDirent(filePath); 2518d05d8e7Sopenharmony_ci if (rmDirentRes) { 2528d05d8e7Sopenharmony_ci return rmDirentRes; 2538d05d8e7Sopenharmony_ci } 2548d05d8e7Sopenharmony_ci } 2558d05d8e7Sopenharmony_ci } 2568d05d8e7Sopenharmony_ci unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> rmdir_req = { 2578d05d8e7Sopenharmony_ci new (nothrow) uv_fs_t, fs_req_cleanup }; 2588d05d8e7Sopenharmony_ci if (!rmdir_req) { 2598d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 2608d05d8e7Sopenharmony_ci return NError(ENOMEM); 2618d05d8e7Sopenharmony_ci } 2628d05d8e7Sopenharmony_ci ret = uv_fs_rmdir(nullptr, rmdir_req.get(), fpath.c_str(), nullptr); 2638d05d8e7Sopenharmony_ci if (ret < 0) { 2648d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to rmdir empty dir, ret: %{public}d", ret); 2658d05d8e7Sopenharmony_ci return NError(ret); 2668d05d8e7Sopenharmony_ci } 2678d05d8e7Sopenharmony_ci return NError(ERRNO_NOERR); 2688d05d8e7Sopenharmony_ci} 2698d05d8e7Sopenharmony_ci 2708d05d8e7Sopenharmony_cistatic int ScanDir(const string &path) 2718d05d8e7Sopenharmony_ci{ 2728d05d8e7Sopenharmony_ci unique_ptr<struct NameListArg, decltype(Deleter)*> pNameList = { new (nothrow) struct NameListArg, Deleter }; 2738d05d8e7Sopenharmony_ci if (!pNameList) { 2748d05d8e7Sopenharmony_ci HILOG_ERROR("Failed to request heap memory."); 2758d05d8e7Sopenharmony_ci return ENOMEM; 2768d05d8e7Sopenharmony_ci } 2778d05d8e7Sopenharmony_ci HILOG_INFO("RecursiveFunc: scandir path = %{public}s", path.c_str()); 2788d05d8e7Sopenharmony_ci return scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort); 2798d05d8e7Sopenharmony_ci} 2808d05d8e7Sopenharmony_ci} // OHOS::FileManagement