• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_core.h"
17 
18 #include <cstdint>
19 #include <cstring>
20 #include <fcntl.h>
21 #include <filesystem>
22 #include <tuple>
23 #include <unistd.h>
24 
25 #include <sys/stat.h>
26 #include <sys/types.h>
27 
28 #include "file_utils.h"
29 #include "filemgmt_libhilog.h"
30 
31 namespace OHOS::FileManagement::ModuleFileIO {
32 using namespace std;
33 
IsAllPath(FileInfo & srcFile,FileInfo & destFile)34 static int32_t IsAllPath(FileInfo &srcFile, FileInfo &destFile)
35 {
36 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
37     filesystem::path srcPath(string(srcFile.path.get()));
38     filesystem::path dstPath(string(destFile.path.get()));
39     error_code errCode;
40     if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing,
41                                errCode)) {
42         HILOGE("Failed to copy file, error code: %{public}d", errCode.value());
43         return errCode.value();
44     }
45 #else
46     std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup) *> copyfileReq = {
47         new (nothrow) uv_fs_t, FsUtils::FsReqCleanup};
48     if (!copyfileReq) {
49         HILOGE("Failed to request heap memory.");
50         return ENOMEM;
51     }
52     int ret = uv_fs_copyfile(nullptr, copyfileReq.get(), srcFile.path.get(), destFile.path.get(),
53                              UV_FS_COPYFILE_FICLONE, nullptr);
54     if (ret < 0) {
55         HILOGE("Failed to copy file when all parameters are paths");
56         return ret;
57     }
58 #endif
59     return ERRNO_NOERR;
60 }
61 
SendFileCore(FileInfo & srcFdg,FileInfo & destFdg,struct stat & statbf)62 static int32_t SendFileCore(FileInfo &srcFdg, FileInfo &destFdg, struct stat &statbf)
63 {
64     std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup) *> sendfileReq = {
65         new (nothrow) uv_fs_t, FsUtils::FsReqCleanup};
66     if (!sendfileReq) {
67         HILOGE("Failed to request heap memory.");
68         return ENOMEM;
69     }
70     int64_t offset = 0;
71     size_t size = static_cast<size_t>(statbf.st_size);
72     int ret = 0;
73     while (size > 0) {
74         ret = uv_fs_sendfile(nullptr, sendfileReq.get(), destFdg.fdg->GetFD(), srcFdg.fdg->GetFD(),
75                              offset, std::min(MAX_SIZE, size), nullptr);
76         if (ret < 0) {
77             HILOGE("Failed to sendfile by ret : %{public}d", ret);
78             return ret;
79         }
80         if (static_cast<size_t>(ret) > size) {
81             HILOGE("More bytes returned than the size of the file. The file size is "
82                    "%{public}zu"
83                    "The bytes returned is %{public}d",
84                    size, ret);
85             return EIO;
86         }
87         offset += static_cast<int64_t>(ret);
88         size -= static_cast<size_t>(ret);
89         if (ret == 0) {
90             break;
91         }
92     }
93     if (size != 0) {
94         HILOGE("The execution of the sendfile task was terminated, remaining file "
95                "size %{public}zu", size);
96         return EIO;
97     }
98     return ERRNO_NOERR;
99 }
100 
TruncateCore(const FileInfo & fileInfo)101 static int32_t TruncateCore(const FileInfo &fileInfo)
102 {
103     std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup) *> ftruncateReq = {
104         new (nothrow) uv_fs_t, FsUtils::FsReqCleanup};
105     if (!ftruncateReq) {
106         HILOGE("Failed to request heap memory.");
107         return ENOMEM;
108     }
109     int ret = uv_fs_ftruncate(nullptr, ftruncateReq.get(), fileInfo.fdg->GetFD(), 0, nullptr);
110     if (ret < 0) {
111         HILOGE("Failed to truncate dstFile with ret: %{public}d", ret);
112         return ret;
113     }
114     return ERRNO_NOERR;
115 }
116 
OpenCore(FileInfo & fileInfo,const int flags,const int mode)117 static int32_t OpenCore(FileInfo &fileInfo, const int flags, const int mode)
118 {
119     std::unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup) *> openReq = {
120         new (nothrow) uv_fs_t, FsUtils::FsReqCleanup};
121     if (!openReq) {
122         HILOGE("Failed to request heap memory.");
123         return ENOMEM;
124     }
125     int ret = uv_fs_open(nullptr, openReq.get(), fileInfo.path.get(), flags, mode, nullptr);
126     if (ret < 0) {
127         HILOGE("Failed to open srcFile with ret: %{public}d", ret);
128         return ret;
129     }
130     fileInfo.fdg = CreateUniquePtr<DistributedFS::FDGuard>(ret, true);
131     if (fileInfo.fdg == nullptr) {
132         HILOGE("Failed to request heap memory.");
133         close(ret);
134         return ENOMEM;
135     }
136     return ERRNO_NOERR;
137 }
138 
OpenFile(FileInfo & srcFile,FileInfo & destFile)139 static int32_t OpenFile(FileInfo &srcFile, FileInfo &destFile)
140 {
141     if (srcFile.isPath) {
142         auto openResult = OpenCore(srcFile, UV_FS_O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
143         if (openResult) {
144             return openResult;
145         }
146     }
147     struct stat statbf;
148     if (fstat(srcFile.fdg->GetFD(), &statbf) < 0) {
149         HILOGE("Failed to get stat of file by fd: %{public}d", srcFile.fdg->GetFD());
150         return errno;
151     }
152     if (destFile.isPath) {
153         auto openResult = OpenCore(destFile, UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC,
154                                    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
155         if (openResult) {
156             return openResult;
157         }
158     } else {
159         auto truncateResult = TruncateCore(destFile);
160         if (truncateResult) {
161             return truncateResult;
162         }
163         auto ret = lseek(destFile.fdg->GetFD(), 0, SEEK_SET);
164         if (ret < 0) {
165             HILOGE("Failed to lseek destFile, errno: %{public}d", errno);
166             return errno;
167         }
168     }
169     if (statbf.st_size == 0) {
170         return ERRNO_NOERR;
171     }
172     return SendFileCore(srcFile, destFile, statbf);
173 }
174 
ValidMode(const optional<int32_t> & mode)175 static tuple<bool, int32_t> ValidMode(const optional<int32_t> &mode)
176 {
177     int modeValue = 0;
178     if (mode.has_value()) {
179         modeValue = mode.value();
180         if (modeValue) {
181             return { false, modeValue };
182         }
183     }
184     return { true, modeValue };
185 }
186 
DoCopyFile(FileInfo & src,FileInfo & dest,const optional<int32_t> & mode)187 FsResult<void> CopyFileCore::DoCopyFile(FileInfo &src, FileInfo &dest,
188     const optional<int32_t> &mode)
189 {
190     auto [succMode, modeValue] = ValidMode(mode);
191     if (!succMode) {
192         HILOGE("Failed to convert mode to int32");
193         return FsResult<void>::Error(EINVAL);
194     }
195 
196     if (src.isPath && dest.isPath) {
197         auto err = IsAllPath(src, dest);
198         if (err) {
199             return FsResult<void>::Error(err);
200         }
201     } else {
202         auto err = OpenFile(src, dest);
203         if (err) {
204             return FsResult<void>::Error(err);
205         }
206     }
207     return FsResult<void>::Success();
208 }
209 
210 } // namespace OHOS::FileManagement::ModuleFileIO