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, &copyfile_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr);
1748d05d8e7Sopenharmony_ci    uv_fs_req_cleanup(&copyfile_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