15bebb993Sopenharmony_ci/*
25bebb993Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
35bebb993Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
45bebb993Sopenharmony_ci * you may not use this file except in compliance with the License.
55bebb993Sopenharmony_ci * You may obtain a copy of the License at
65bebb993Sopenharmony_ci *
75bebb993Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
85bebb993Sopenharmony_ci *
95bebb993Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
105bebb993Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
115bebb993Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
125bebb993Sopenharmony_ci * See the License for the specific language governing permissions and
135bebb993Sopenharmony_ci * limitations under the License.
145bebb993Sopenharmony_ci */
155bebb993Sopenharmony_ci
165bebb993Sopenharmony_ci#include "copy_file.h"
175bebb993Sopenharmony_ci#include "stat_impl.h"
185bebb993Sopenharmony_ci#include "macro.h"
195bebb993Sopenharmony_ci#include "n_error.h"
205bebb993Sopenharmony_ci
215bebb993Sopenharmony_ci#include <cstring>
225bebb993Sopenharmony_ci#include <fcntl.h>
235bebb993Sopenharmony_ci#include <filesystem>
245bebb993Sopenharmony_ci#include <sys/stat.h>
255bebb993Sopenharmony_ci#include <sys/types.h>
265bebb993Sopenharmony_ci#include <tuple>
275bebb993Sopenharmony_ci#include <unistd.h>
285bebb993Sopenharmony_ci
295bebb993Sopenharmony_cinamespace OHOS {
305bebb993Sopenharmony_cinamespace CJSystemapi {
315bebb993Sopenharmony_ciusing namespace std;
325bebb993Sopenharmony_ciusing namespace OHOS::FileManagement::LibN;
335bebb993Sopenharmony_ciusing namespace OHOS::FileManagement;
345bebb993Sopenharmony_ciusing namespace OHOS::CJSystemapi::FileFs;
355bebb993Sopenharmony_ci
365bebb993Sopenharmony_cistd::tuple<int, FileInfo> ParseOperand(int32_t file)
375bebb993Sopenharmony_ci{
385bebb993Sopenharmony_ci    LOGI("FS_TEST:: FS_TEST::ParseOperand");
395bebb993Sopenharmony_ci    if (file < 0) {
405bebb993Sopenharmony_ci        LOGE("Invalid fd");
415bebb993Sopenharmony_ci        return { EINVAL, FileInfo { false, {}, {} } };
425bebb993Sopenharmony_ci    }
435bebb993Sopenharmony_ci    auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(file, false);
445bebb993Sopenharmony_ci    if (fdg == nullptr) {
455bebb993Sopenharmony_ci        LOGE("Failed to request heap memory.");
465bebb993Sopenharmony_ci        return { ENOMEM, FileInfo { false, {}, {} } };
475bebb993Sopenharmony_ci    }
485bebb993Sopenharmony_ci    LOGI("FS_TEST:: FS_TEST::ParseOperand success");
495bebb993Sopenharmony_ci    return { SUCCESS_CODE, FileInfo { false, {}, move(fdg) } };
505bebb993Sopenharmony_ci};
515bebb993Sopenharmony_ci
525bebb993Sopenharmony_cistd::tuple<int, FileInfo> ParseOperand(std::string file)
535bebb993Sopenharmony_ci{
545bebb993Sopenharmony_ci    LOGI("FS_TEST:: ParseOperand");
555bebb993Sopenharmony_ci    std::unique_ptr<char[]> filePath = std::make_unique<char[]>(file.length() + 1);
565bebb993Sopenharmony_ci    if (!filePath) {
575bebb993Sopenharmony_ci        return { ENOMEM, FileInfo { true, {}, {} } };
585bebb993Sopenharmony_ci    }
595bebb993Sopenharmony_ci    for (size_t i = 0; i < file.length(); i++) {
605bebb993Sopenharmony_ci        filePath[i] = file[i];
615bebb993Sopenharmony_ci    }
625bebb993Sopenharmony_ci
635bebb993Sopenharmony_ci    LOGI("FS_TEST:: ParseOperand success");
645bebb993Sopenharmony_ci    return { SUCCESS_CODE, FileInfo { true, move(filePath), {} } };
655bebb993Sopenharmony_ci};
665bebb993Sopenharmony_ci
675bebb993Sopenharmony_cistatic int IsAllPath(FileInfo& srcFile, FileInfo& destFile)
685bebb993Sopenharmony_ci{
695bebb993Sopenharmony_ci#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
705bebb993Sopenharmony_ci    filesystem::path srcPath(string(srcFile.path.get()));
715bebb993Sopenharmony_ci    filesystem::path dstPath(string(destFile.path.get()));
725bebb993Sopenharmony_ci    error_code errCode;
735bebb993Sopenharmony_ci    LOGI("srcPath: %{public}s", srcPath.c_str());
745bebb993Sopenharmony_ci    LOGI("dstPath: %{public}s", dstPath.c_str());
755bebb993Sopenharmony_ci    if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) {
765bebb993Sopenharmony_ci        LOGE("Failed to copy file, error code: %{public}d", errCode.value());
775bebb993Sopenharmony_ci        return errCode.value();
785bebb993Sopenharmony_ci    }
795bebb993Sopenharmony_ci#else
805bebb993Sopenharmony_ci    std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> copyfile_req = {
815bebb993Sopenharmony_ci        new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
825bebb993Sopenharmony_ci    if (!copyfile_req) {
835bebb993Sopenharmony_ci        LOGE("Failed to request heap memory.");
845bebb993Sopenharmony_ci        return ENOMEM;
855bebb993Sopenharmony_ci    }
865bebb993Sopenharmony_ci    int ret = uv_fs_copyfile(nullptr, copyfile_req.get(), srcFile.path.get(), destFile.path.get(),
875bebb993Sopenharmony_ci                             UV_FS_COPYFILE_FICLONE, nullptr);
885bebb993Sopenharmony_ci    if (ret < 0) {
895bebb993Sopenharmony_ci        LOGE("Failed to copy file when all parameters are paths");
905bebb993Sopenharmony_ci        return ret;
915bebb993Sopenharmony_ci    }
925bebb993Sopenharmony_ci#endif
935bebb993Sopenharmony_ci    return OHOS::FileManagement::LibN::ERRNO_NOERR;
945bebb993Sopenharmony_ci}
955bebb993Sopenharmony_ci
965bebb993Sopenharmony_cistatic int SendFileCore(FileInfo& srcFdg, FileInfo& destFdg, struct stat& statbf)
975bebb993Sopenharmony_ci{
985bebb993Sopenharmony_ci    std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> sendfile_req = {
995bebb993Sopenharmony_ci        new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1005bebb993Sopenharmony_ci    if (!sendfile_req) {
1015bebb993Sopenharmony_ci        LOGE("Failed to request heap memory.");
1025bebb993Sopenharmony_ci        return ENOMEM;
1035bebb993Sopenharmony_ci    }
1045bebb993Sopenharmony_ci    int64_t offset = 0;
1055bebb993Sopenharmony_ci    size_t size = static_cast<size_t>(statbf.st_size);
1065bebb993Sopenharmony_ci    while (size > 0) {
1075bebb993Sopenharmony_ci        int ret = uv_fs_sendfile(nullptr, sendfile_req.get(), destFdg.fdg->GetFD(), srcFdg.fdg->GetFD(),
1085bebb993Sopenharmony_ci            offset, MAX_SIZE, nullptr);
1095bebb993Sopenharmony_ci        if (ret < 0) {
1105bebb993Sopenharmony_ci            LOGE("Failed to sendfile by ret : %{public}d", ret);
1115bebb993Sopenharmony_ci            return ret;
1125bebb993Sopenharmony_ci        }
1135bebb993Sopenharmony_ci        offset += static_cast<int64_t>(ret);
1145bebb993Sopenharmony_ci        size -= static_cast<size_t>(ret);
1155bebb993Sopenharmony_ci        if (ret == 0) {
1165bebb993Sopenharmony_ci            break;
1175bebb993Sopenharmony_ci        }
1185bebb993Sopenharmony_ci    }
1195bebb993Sopenharmony_ci    if (size != 0) {
1205bebb993Sopenharmony_ci        LOGE("The execution of the sendfile task was terminated, remaining file size %{public}zu", size);
1215bebb993Sopenharmony_ci        return EIO;
1225bebb993Sopenharmony_ci    }
1235bebb993Sopenharmony_ci    return OHOS::FileManagement::LibN::ERRNO_NOERR;
1245bebb993Sopenharmony_ci}
1255bebb993Sopenharmony_ci
1265bebb993Sopenharmony_cistatic int TruncateCore(const FileInfo& fileInfo)
1275bebb993Sopenharmony_ci{
1285bebb993Sopenharmony_ci    std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> ftruncate_req = {
1295bebb993Sopenharmony_ci        new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1305bebb993Sopenharmony_ci    if (!ftruncate_req) {
1315bebb993Sopenharmony_ci        LOGE("Failed to request heap memory.");
1325bebb993Sopenharmony_ci        return 1;
1335bebb993Sopenharmony_ci    }
1345bebb993Sopenharmony_ci    int ret = uv_fs_ftruncate(nullptr, ftruncate_req.get(), fileInfo.fdg->GetFD(), 0, nullptr);
1355bebb993Sopenharmony_ci    if (ret < 0) {
1365bebb993Sopenharmony_ci        LOGE("Failed to truncate dstFile with ret: %{public}d", ret);
1375bebb993Sopenharmony_ci        return 1;
1385bebb993Sopenharmony_ci    }
1395bebb993Sopenharmony_ci    return 0;
1405bebb993Sopenharmony_ci}
1415bebb993Sopenharmony_ci
1425bebb993Sopenharmony_cistatic int OpenCore(FileInfo& fileInfo, const int flags, const int mode)
1435bebb993Sopenharmony_ci{
1445bebb993Sopenharmony_ci    std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> open_req = {
1455bebb993Sopenharmony_ci        new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup };
1465bebb993Sopenharmony_ci    if (!open_req) {
1475bebb993Sopenharmony_ci        LOGE("Failed to request heap memory.");
1485bebb993Sopenharmony_ci        return 1;
1495bebb993Sopenharmony_ci    }
1505bebb993Sopenharmony_ci    int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), flags, mode, nullptr);
1515bebb993Sopenharmony_ci    if (ret < 0) {
1525bebb993Sopenharmony_ci        LOGE("Failed to open srcFile with ret: %{public}d", ret);
1535bebb993Sopenharmony_ci        return 1;
1545bebb993Sopenharmony_ci    }
1555bebb993Sopenharmony_ci    fileInfo.fdg = CreateUniquePtr<DistributedFS::FDGuard>(ret, true);
1565bebb993Sopenharmony_ci    if (fileInfo.fdg == nullptr) {
1575bebb993Sopenharmony_ci        LOGE("Failed to request heap memory.");
1585bebb993Sopenharmony_ci        close(ret);
1595bebb993Sopenharmony_ci        return 1;
1605bebb993Sopenharmony_ci    }
1615bebb993Sopenharmony_ci    return 0;
1625bebb993Sopenharmony_ci}
1635bebb993Sopenharmony_ci
1645bebb993Sopenharmony_cistatic int OpenFile(FileInfo& srcFile, FileInfo& destFile)
1655bebb993Sopenharmony_ci{
1665bebb993Sopenharmony_ci    if (srcFile.isPath) {
1675bebb993Sopenharmony_ci        auto openResult = OpenCore(srcFile, UV_FS_O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
1685bebb993Sopenharmony_ci        if (openResult) {
1695bebb993Sopenharmony_ci            return openResult;
1705bebb993Sopenharmony_ci        }
1715bebb993Sopenharmony_ci    }
1725bebb993Sopenharmony_ci    struct stat statbf;
1735bebb993Sopenharmony_ci    if (fstat(srcFile.fdg->GetFD(), &statbf) < 0) {
1745bebb993Sopenharmony_ci        LOGE("Failed to get stat of file by fd: %{public}d", srcFile.fdg->GetFD());
1755bebb993Sopenharmony_ci        return errno;
1765bebb993Sopenharmony_ci    }
1775bebb993Sopenharmony_ci    if (destFile.isPath) {
1785bebb993Sopenharmony_ci        auto openResult = OpenCore(destFile, UV_FS_O_RDWR | UV_FS_O_CREAT |
1795bebb993Sopenharmony_ci            UV_FS_O_TRUNC, statbf.st_mode);
1805bebb993Sopenharmony_ci        if (openResult) {
1815bebb993Sopenharmony_ci            return openResult;
1825bebb993Sopenharmony_ci        }
1835bebb993Sopenharmony_ci    } else {
1845bebb993Sopenharmony_ci        auto truncateResult = TruncateCore(destFile);
1855bebb993Sopenharmony_ci        if (truncateResult) {
1865bebb993Sopenharmony_ci            return truncateResult;
1875bebb993Sopenharmony_ci        }
1885bebb993Sopenharmony_ci        auto ret = lseek(destFile.fdg->GetFD(), 0, SEEK_SET);
1895bebb993Sopenharmony_ci        if (ret < 0) {
1905bebb993Sopenharmony_ci            LOGE("Failed to lseek destFile, errno: %{public}d", errno);
1915bebb993Sopenharmony_ci            return errno;
1925bebb993Sopenharmony_ci        }
1935bebb993Sopenharmony_ci    }
1945bebb993Sopenharmony_ci    return SendFileCore(srcFile, destFile, statbf);
1955bebb993Sopenharmony_ci}
1965bebb993Sopenharmony_ci
1975bebb993Sopenharmony_ciint CopyFileImpl::CopyFile(const std::string& src, const std::string& dest, int mode)
1985bebb993Sopenharmony_ci{
1995bebb993Sopenharmony_ci    LOGI("FS_TEST:: CopyFile::CopyFile start");
2005bebb993Sopenharmony_ci    auto [succSrc, srcFileInfo] = ParseOperand(src);
2015bebb993Sopenharmony_ci    if (succSrc != SUCCESS_CODE) {
2025bebb993Sopenharmony_ci        return succSrc;
2035bebb993Sopenharmony_ci    }
2045bebb993Sopenharmony_ci    auto [succDest, destFileInfo] = ParseOperand(dest);
2055bebb993Sopenharmony_ci    if (succDest != SUCCESS_CODE) {
2065bebb993Sopenharmony_ci        return succDest;
2075bebb993Sopenharmony_ci    }
2085bebb993Sopenharmony_ci    return IsAllPath(srcFileInfo, destFileInfo);
2095bebb993Sopenharmony_ci}
2105bebb993Sopenharmony_ci
2115bebb993Sopenharmony_ciint CopyFileImpl::CopyFile(const std::string& src, int32_t dest, int mode)
2125bebb993Sopenharmony_ci{
2135bebb993Sopenharmony_ci    LOGI("FS_TEST:: CopyFile::CopyFile start");
2145bebb993Sopenharmony_ci    auto [succSrc, srcFileInfo] = ParseOperand(src);
2155bebb993Sopenharmony_ci    if (succSrc != SUCCESS_CODE) {
2165bebb993Sopenharmony_ci        return succSrc;
2175bebb993Sopenharmony_ci    }
2185bebb993Sopenharmony_ci    auto [succDest, destFileInfo] = ParseOperand(dest);
2195bebb993Sopenharmony_ci    if (succDest != SUCCESS_CODE) {
2205bebb993Sopenharmony_ci        return succDest;
2215bebb993Sopenharmony_ci    }
2225bebb993Sopenharmony_ci    return OpenFile(srcFileInfo, destFileInfo);
2235bebb993Sopenharmony_ci}
2245bebb993Sopenharmony_ci
2255bebb993Sopenharmony_ciint CopyFileImpl::CopyFile(int32_t src, const std::string& dest, int mode)
2265bebb993Sopenharmony_ci{
2275bebb993Sopenharmony_ci    LOGI("FS_TEST:: CopyFile::CopyFile start");
2285bebb993Sopenharmony_ci    auto [succSrc, srcFileInfo] = ParseOperand(src);
2295bebb993Sopenharmony_ci    if (succSrc != SUCCESS_CODE) {
2305bebb993Sopenharmony_ci        return succSrc;
2315bebb993Sopenharmony_ci    }
2325bebb993Sopenharmony_ci    auto [succDest, destFileInfo] = ParseOperand(dest);
2335bebb993Sopenharmony_ci    if (succDest != SUCCESS_CODE) {
2345bebb993Sopenharmony_ci        return succDest;
2355bebb993Sopenharmony_ci    }
2365bebb993Sopenharmony_ci    return OpenFile(srcFileInfo, destFileInfo);
2375bebb993Sopenharmony_ci}
2385bebb993Sopenharmony_ci
2395bebb993Sopenharmony_ciint CopyFileImpl::CopyFile(int32_t src, int32_t dest, int mode)
2405bebb993Sopenharmony_ci{
2415bebb993Sopenharmony_ci    LOGI("FS_TEST:: CopyFile::CopyFile start");
2425bebb993Sopenharmony_ci    auto [succSrc, srcFileInfo] = ParseOperand(src);
2435bebb993Sopenharmony_ci    if (succSrc != SUCCESS_CODE) {
2445bebb993Sopenharmony_ci        return succSrc;
2455bebb993Sopenharmony_ci    }
2465bebb993Sopenharmony_ci    auto [succDest, destFileInfo] = ParseOperand(dest);
2475bebb993Sopenharmony_ci    if (succDest != SUCCESS_CODE) {
2485bebb993Sopenharmony_ci        return succDest;
2495bebb993Sopenharmony_ci    }
2505bebb993Sopenharmony_ci    return OpenFile(srcFileInfo, destFileInfo);
2515bebb993Sopenharmony_ci}
2525bebb993Sopenharmony_ci
2535bebb993Sopenharmony_ci}
2545bebb993Sopenharmony_ci}