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}