1/* 2 * Copyright (c) 2024 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 "copy_file.h" 17#include "stat_impl.h" 18#include "macro.h" 19#include "n_error.h" 20 21#include <cstring> 22#include <fcntl.h> 23#include <filesystem> 24#include <sys/stat.h> 25#include <sys/types.h> 26#include <tuple> 27#include <unistd.h> 28 29namespace OHOS { 30namespace CJSystemapi { 31using namespace std; 32using namespace OHOS::FileManagement::LibN; 33using namespace OHOS::FileManagement; 34using namespace OHOS::CJSystemapi::FileFs; 35 36std::tuple<int, FileInfo> ParseOperand(int32_t file) 37{ 38 LOGI("FS_TEST:: FS_TEST::ParseOperand"); 39 if (file < 0) { 40 LOGE("Invalid fd"); 41 return { EINVAL, FileInfo { false, {}, {} } }; 42 } 43 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(file, false); 44 if (fdg == nullptr) { 45 LOGE("Failed to request heap memory."); 46 return { ENOMEM, FileInfo { false, {}, {} } }; 47 } 48 LOGI("FS_TEST:: FS_TEST::ParseOperand success"); 49 return { SUCCESS_CODE, FileInfo { false, {}, move(fdg) } }; 50}; 51 52std::tuple<int, FileInfo> ParseOperand(std::string file) 53{ 54 LOGI("FS_TEST:: ParseOperand"); 55 std::unique_ptr<char[]> filePath = std::make_unique<char[]>(file.length() + 1); 56 if (!filePath) { 57 return { ENOMEM, FileInfo { true, {}, {} } }; 58 } 59 for (size_t i = 0; i < file.length(); i++) { 60 filePath[i] = file[i]; 61 } 62 63 LOGI("FS_TEST:: ParseOperand success"); 64 return { SUCCESS_CODE, FileInfo { true, move(filePath), {} } }; 65}; 66 67static int IsAllPath(FileInfo& srcFile, FileInfo& destFile) 68{ 69#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) 70 filesystem::path srcPath(string(srcFile.path.get())); 71 filesystem::path dstPath(string(destFile.path.get())); 72 error_code errCode; 73 LOGI("srcPath: %{public}s", srcPath.c_str()); 74 LOGI("dstPath: %{public}s", dstPath.c_str()); 75 if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) { 76 LOGE("Failed to copy file, error code: %{public}d", errCode.value()); 77 return errCode.value(); 78 } 79#else 80 std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> copyfile_req = { 81 new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 82 if (!copyfile_req) { 83 LOGE("Failed to request heap memory."); 84 return ENOMEM; 85 } 86 int ret = uv_fs_copyfile(nullptr, copyfile_req.get(), srcFile.path.get(), destFile.path.get(), 87 UV_FS_COPYFILE_FICLONE, nullptr); 88 if (ret < 0) { 89 LOGE("Failed to copy file when all parameters are paths"); 90 return ret; 91 } 92#endif 93 return OHOS::FileManagement::LibN::ERRNO_NOERR; 94} 95 96static int SendFileCore(FileInfo& srcFdg, FileInfo& destFdg, struct stat& statbf) 97{ 98 std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> sendfile_req = { 99 new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 100 if (!sendfile_req) { 101 LOGE("Failed to request heap memory."); 102 return ENOMEM; 103 } 104 int64_t offset = 0; 105 size_t size = static_cast<size_t>(statbf.st_size); 106 while (size > 0) { 107 int ret = uv_fs_sendfile(nullptr, sendfile_req.get(), destFdg.fdg->GetFD(), srcFdg.fdg->GetFD(), 108 offset, MAX_SIZE, nullptr); 109 if (ret < 0) { 110 LOGE("Failed to sendfile by ret : %{public}d", ret); 111 return ret; 112 } 113 offset += static_cast<int64_t>(ret); 114 size -= static_cast<size_t>(ret); 115 if (ret == 0) { 116 break; 117 } 118 } 119 if (size != 0) { 120 LOGE("The execution of the sendfile task was terminated, remaining file size %{public}zu", size); 121 return EIO; 122 } 123 return OHOS::FileManagement::LibN::ERRNO_NOERR; 124} 125 126static int TruncateCore(const FileInfo& fileInfo) 127{ 128 std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> ftruncate_req = { 129 new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 130 if (!ftruncate_req) { 131 LOGE("Failed to request heap memory."); 132 return 1; 133 } 134 int ret = uv_fs_ftruncate(nullptr, ftruncate_req.get(), fileInfo.fdg->GetFD(), 0, nullptr); 135 if (ret < 0) { 136 LOGE("Failed to truncate dstFile with ret: %{public}d", ret); 137 return 1; 138 } 139 return 0; 140} 141 142static int OpenCore(FileInfo& fileInfo, const int flags, const int mode) 143{ 144 std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> open_req = { 145 new (nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 146 if (!open_req) { 147 LOGE("Failed to request heap memory."); 148 return 1; 149 } 150 int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), flags, mode, nullptr); 151 if (ret < 0) { 152 LOGE("Failed to open srcFile with ret: %{public}d", ret); 153 return 1; 154 } 155 fileInfo.fdg = CreateUniquePtr<DistributedFS::FDGuard>(ret, true); 156 if (fileInfo.fdg == nullptr) { 157 LOGE("Failed to request heap memory."); 158 close(ret); 159 return 1; 160 } 161 return 0; 162} 163 164static int OpenFile(FileInfo& srcFile, FileInfo& destFile) 165{ 166 if (srcFile.isPath) { 167 auto openResult = OpenCore(srcFile, UV_FS_O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 168 if (openResult) { 169 return openResult; 170 } 171 } 172 struct stat statbf; 173 if (fstat(srcFile.fdg->GetFD(), &statbf) < 0) { 174 LOGE("Failed to get stat of file by fd: %{public}d", srcFile.fdg->GetFD()); 175 return errno; 176 } 177 if (destFile.isPath) { 178 auto openResult = OpenCore(destFile, UV_FS_O_RDWR | UV_FS_O_CREAT | 179 UV_FS_O_TRUNC, statbf.st_mode); 180 if (openResult) { 181 return openResult; 182 } 183 } else { 184 auto truncateResult = TruncateCore(destFile); 185 if (truncateResult) { 186 return truncateResult; 187 } 188 auto ret = lseek(destFile.fdg->GetFD(), 0, SEEK_SET); 189 if (ret < 0) { 190 LOGE("Failed to lseek destFile, errno: %{public}d", errno); 191 return errno; 192 } 193 } 194 return SendFileCore(srcFile, destFile, statbf); 195} 196 197int CopyFileImpl::CopyFile(const std::string& src, const std::string& dest, int mode) 198{ 199 LOGI("FS_TEST:: CopyFile::CopyFile start"); 200 auto [succSrc, srcFileInfo] = ParseOperand(src); 201 if (succSrc != SUCCESS_CODE) { 202 return succSrc; 203 } 204 auto [succDest, destFileInfo] = ParseOperand(dest); 205 if (succDest != SUCCESS_CODE) { 206 return succDest; 207 } 208 return IsAllPath(srcFileInfo, destFileInfo); 209} 210 211int CopyFileImpl::CopyFile(const std::string& src, int32_t dest, int mode) 212{ 213 LOGI("FS_TEST:: CopyFile::CopyFile start"); 214 auto [succSrc, srcFileInfo] = ParseOperand(src); 215 if (succSrc != SUCCESS_CODE) { 216 return succSrc; 217 } 218 auto [succDest, destFileInfo] = ParseOperand(dest); 219 if (succDest != SUCCESS_CODE) { 220 return succDest; 221 } 222 return OpenFile(srcFileInfo, destFileInfo); 223} 224 225int CopyFileImpl::CopyFile(int32_t src, const std::string& dest, int mode) 226{ 227 LOGI("FS_TEST:: CopyFile::CopyFile start"); 228 auto [succSrc, srcFileInfo] = ParseOperand(src); 229 if (succSrc != SUCCESS_CODE) { 230 return succSrc; 231 } 232 auto [succDest, destFileInfo] = ParseOperand(dest); 233 if (succDest != SUCCESS_CODE) { 234 return succDest; 235 } 236 return OpenFile(srcFileInfo, destFileInfo); 237} 238 239int CopyFileImpl::CopyFile(int32_t src, int32_t dest, int mode) 240{ 241 LOGI("FS_TEST:: CopyFile::CopyFile start"); 242 auto [succSrc, srcFileInfo] = ParseOperand(src); 243 if (succSrc != SUCCESS_CODE) { 244 return succSrc; 245 } 246 auto [succDest, destFileInfo] = ParseOperand(dest); 247 if (succDest != SUCCESS_CODE) { 248 return succDest; 249 } 250 return OpenFile(srcFileInfo, destFileInfo); 251} 252 253} 254}