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
29 namespace OHOS {
30 namespace CJSystemapi {
31 using namespace std;
32 using namespace OHOS::FileManagement::LibN;
33 using namespace OHOS::FileManagement;
34 using namespace OHOS::CJSystemapi::FileFs;
35
ParseOperand(int32_t file)36 std::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
ParseOperand(std::string file)52 std::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
IsAllPath(FileInfo & srcFile,FileInfo & destFile)67 static 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
SendFileCore(FileInfo & srcFdg,FileInfo & destFdg,struct stat & statbf)96 static 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
TruncateCore(const FileInfo & fileInfo)126 static 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
OpenCore(FileInfo & fileInfo,const int flags,const int mode)142 static 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
OpenFile(FileInfo & srcFile,FileInfo & destFile)164 static 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
CopyFile(const std::string & src,const std::string & dest,int mode)197 int 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
CopyFile(const std::string & src,int32_t dest,int mode)211 int 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
CopyFile(int32_t src,const std::string & dest,int mode)225 int 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
CopyFile(int32_t src,int32_t dest,int mode)239 int 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 }