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 "pasteboard_copy.h"
17
18 #include <filesystem>
19 #include "copy/file_copy_manager.h"
20 #include "copy/file_size_utils.h"
21 #include "file_uri.h"
22 #include "paste_data.h"
23 #include "paste_data_record.h"
24 #include "pasteboard_error.h"
25 #include "pasteboard_hilog.h"
26
27 namespace OHOS {
28 namespace MiscServices {
29 using namespace AppFileService::ModuleFileUri;
30 const std::string NETWORK_PARA = "?networkid=";
31 constexpr int PERCENTAGE = 100;
32 constexpr int ERRNO_NOERR = 0;
33 constexpr int E_EXIST = 17;
34 constexpr float FILE_PERCENTAGE = 0.8;
35 constexpr int BEGIN_PERCENTAGE = 20;
36 constexpr int DFS_CANCEL_SUCCESS = 204;
37
38 static int32_t g_recordSize = 0;
39 ProgressListener PasteBoardCopyFile::progressListener_;
40
GetInstance()41 PasteBoardCopyFile &PasteBoardCopyFile::GetInstance()
42 {
43 static PasteBoardCopyFile instance;
44 return instance;
45 }
46
IsDirectory(const std::string & path)47 bool PasteBoardCopyFile::IsDirectory(const std::string &path)
48 {
49 struct stat buf {};
50 int ret = stat(path.c_str(), &buf);
51 if (ret == -1) {
52 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Stat failed. errno=%{public}d", errno);
53 return false;
54 }
55 return (buf.st_mode & S_IFMT) == S_IFDIR;
56 }
57
IsFile(const std::string & path)58 bool PasteBoardCopyFile::IsFile(const std::string &path)
59 {
60 struct stat buf {};
61 int ret = stat(path.c_str(), &buf);
62 if (ret == -1) {
63 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Stat failed. errno = %{public}d", errno);
64 return false;
65 }
66 return (buf.st_mode & S_IFMT) == S_IFREG;
67 }
68
OnProgressNotify(std::shared_ptr<GetDataParams> params)69 void PasteBoardCopyFile::OnProgressNotify(std::shared_ptr<GetDataParams> params)
70 {
71 if (params == nullptr) {
72 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "params is null!");
73 return;
74 }
75
76 if (params->info == nullptr) {
77 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "params->info is null!");
78 return;
79 }
80
81 if (params->info->percentage > PERCENTAGE) {
82 params->info->percentage = PERCENTAGE;
83 }
84 params->info->percentage = static_cast<int32_t>(params->info->percentage * FILE_PERCENTAGE + BEGIN_PERCENTAGE);
85 params->info->percentage = std::abs(params->info->percentage);
86 params->info->percentage = std::max(params->info->percentage, 0);
87 if (progressListener_.ProgressNotify != nullptr) {
88 progressListener_.ProgressNotify(params);
89 } else {
90 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "ProgressNotify is nullptr.");
91 }
92 }
93
GetRealPath(const std::string & path)94 std::string PasteBoardCopyFile::GetRealPath(const std::string& path)
95 {
96 std::filesystem::path tempPath(path);
97 std::filesystem::path realPath{};
98 for (const auto& component : tempPath) {
99 if (component == ".") {
100 continue;
101 } else if (component == "..") {
102 realPath = realPath.parent_path();
103 } else {
104 realPath /= component;
105 }
106 }
107 return realPath.string();
108 }
109
IsRemoteUri(const std::string & uri)110 bool PasteBoardCopyFile::IsRemoteUri(const std::string &uri)
111 {
112 return uri.find(NETWORK_PARA) != uri.npos;
113 }
114
CheckCopyParam(PasteData & pasteData,std::shared_ptr<GetDataParams> dataParams)115 int32_t PasteBoardCopyFile::CheckCopyParam(PasteData &pasteData, std::shared_ptr<GetDataParams> dataParams)
116 {
117 if (dataParams == nullptr) {
118 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Invalid dataParams");
119 return static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR);
120 }
121 g_recordSize = (int32_t)pasteData.GetRecordCount();
122 if (g_recordSize <= 0) {
123 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Invalid records size");
124 return static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR);
125 }
126 return static_cast<int32_t>(PasteboardError::E_OK);
127 }
128
InitCopyInfo(const std::string srcUri,std::shared_ptr<GetDataParams> dataParams,std::shared_ptr<CopyInfo> copyInfo,int32_t index)129 int32_t PasteBoardCopyFile::InitCopyInfo(const std::string srcUri, std::shared_ptr<GetDataParams> dataParams,
130 std::shared_ptr<CopyInfo> copyInfo, int32_t index)
131 {
132 copyInfo->srcUri = srcUri;
133 copyInfo->destUri = dataParams->destUri;
134 FileUri srcFileUri(copyInfo->srcUri);
135 copyInfo->srcPath = srcFileUri.GetRealPath();
136 FileUri destFileUri(copyInfo->destUri);
137 copyInfo->destPath = destFileUri.GetPath();
138 copyInfo->srcPath = GetRealPath(copyInfo->srcPath);
139 copyInfo->destPath = GetRealPath(copyInfo->destPath);
140 std::string realSrc = copyInfo->srcPath;
141 if (IsRemoteUri(copyInfo->srcUri)) {
142 uint32_t index = copyInfo->srcPath.rfind("?", 0);
143 realSrc = copyInfo->srcPath.substr(0, index);
144 }
145 if (IsDirectory(copyInfo->destPath)) {
146 std::filesystem::path filePath(realSrc);
147 auto fileName = filePath.filename();
148 if (copyInfo->destUri.back() != '/') {
149 copyInfo->destUri += '/';
150 }
151 copyInfo->destUri += fileName.string();
152 FileUri realDest(copyInfo->destUri);
153 copyInfo->destPath = realDest.GetPath();
154 copyInfo->destPath = GetRealPath(copyInfo->destPath);
155 }
156 std::error_code errCode;
157 if (std::filesystem::exists(copyInfo->destPath, errCode) && errCode.value() == ERRNO_NOERR &&
158 dataParams->fileConflictOption == FILE_SKIP) {
159 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "File has existed.");
160 copyInfo->isExist = true;
161 return E_EXIST;
162 }
163 FileUri realFileUri(realSrc);
164 std::string realPath = realFileUri.GetRealPath();
165 realPath = GetRealPath(realPath);
166 if (!IsFile(realPath)) {
167 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "Softbus not support dir to remote.");
168 return ENOMEM;
169 }
170 return ERRNO_NOERR;
171 }
172
CopyFileData(PasteData & pasteData,std::shared_ptr<GetDataParams> dataParams)173 int32_t PasteBoardCopyFile::CopyFileData(PasteData &pasteData, std::shared_ptr<GetDataParams> dataParams)
174 {
175 int32_t ret = static_cast<int32_t>(PasteboardError::E_OK);
176 progressListener_ = dataParams->listener;
177 std::shared_ptr<PasteDataRecord> record = std::make_shared<PasteDataRecord>();
178 int32_t recordCount = 0;
179 int32_t recordProcessedIndex = 0;
180 for (size_t index = 0; index < pasteData.GetRecordCount();) {
181 recordProcessedIndex++;
182 if (ProgressSignalClient::GetInstance().CheckCancelIfNeed()) {
183 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "canceled success!");
184 pasteData.RemoveRecordAt(index);
185 continue;
186 }
187 record = pasteData.GetRecordAt(index);
188 if (record == nullptr) {
189 return static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR);
190 }
191 std::shared_ptr<OHOS::Uri> uri = record->GetUri();
192 if (uri == nullptr) {
193 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "Record has no uri");
194 index++;
195 continue;
196 }
197 std::shared_ptr<CopyInfo> copyInfo = std::make_shared<CopyInfo>();
198 std::string srcUri = uri->ToString();
199 if (InitCopyInfo(srcUri, dataParams, copyInfo, recordCount) == E_EXIST) {
200 recordCount++;
201 pasteData.RemoveRecordAt(index);
202 continue;
203 }
204 recordCount++;
205 CopyInfo info = *copyInfo;
206 using ProcessCallBack = std::function<void(uint64_t processSize, uint64_t totalSize)>;
207 ProcessCallBack listener = [&](uint64_t processSize, uint64_t totalSize) {
208 HandleProgress(recordProcessedIndex, info, processSize, totalSize, dataParams);
209 };
210 ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Copy(srcUri, copyInfo->destUri, listener);
211 if ((ret == static_cast<int32_t>(PasteboardError::E_OK) || ret == ERRNO_NOERR) && !copyInfo->isExist &&
212 !ProgressSignalClient::GetInstance().CheckCancelIfNeed()) {
213 auto sharedUri = std::make_shared<OHOS::Uri>(copyInfo->destUri);
214 record->SetUri(sharedUri);
215 record->SetConvertUri("");
216 index++;
217 } else {
218 pasteData.RemoveRecordAt(index);
219 }
220 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "DFS copy ret: %{public}d", ret);
221 }
222 return (ret == ERRNO_NOERR || ret == DFS_CANCEL_SUCCESS) ? static_cast<int32_t>(PasteboardError::E_OK) : ret;
223 }
224
HandleProgress(int32_t index,CopyInfo & info,uint64_t processSize,uint64_t totalSize,std::shared_ptr<GetDataParams> dataParams)225 void PasteBoardCopyFile::HandleProgress(int32_t index, CopyInfo &info, uint64_t processSize, uint64_t totalSize,
226 std::shared_ptr<GetDataParams> dataParams)
227 {
228 if (dataParams == nullptr) {
229 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "dataParams is nullptr.");
230 return;
231 }
232
233 if (dataParams->info == nullptr) {
234 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "dataParams->info is nullptr.");
235 return;
236 }
237
238 if (index < 1 || totalSize == 0) {
239 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "invalid parameter");
240 return;
241 }
242
243 if (g_recordSize == 0) {
244 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "no record");
245 return;
246 }
247
248 if (ProgressSignalClient::GetInstance().CheckCancelIfNeed()) {
249 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "Cancel copy.");
250 std::thread([&]() {
251 auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Cancel(info.srcUri, info.destUri);
252 if (ret != ERRNO_NOERR) {
253 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Cancel failed. errno=%{public}d", ret);
254 }
255 }).detach();
256 return;
257 }
258
259 int32_t percentage = (int32_t)((PERCENTAGE * processSize) / totalSize);
260 int32_t totalProgress = ((index - 1) * PERCENTAGE + percentage) / g_recordSize;
261 dataParams->info->percentage = totalProgress;
262
263 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "process record index:%{public}d/%{public}d, progress=%{public}d",
264 index, g_recordSize, totalProgress);
265 OnProgressNotify(dataParams);
266 }
267
CopyPasteData(PasteData & pasteData,std::shared_ptr<GetDataParams> dataParams)268 int32_t PasteBoardCopyFile::CopyPasteData(PasteData &pasteData, std::shared_ptr<GetDataParams> dataParams)
269 {
270 g_recordSize = 0;
271 int32_t ret = CheckCopyParam(pasteData, dataParams);
272 if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
273 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Invalid copy params");
274 g_recordSize = 0;
275 return ret;
276 }
277 ret = CopyFileData(pasteData, dataParams);
278 if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
279 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "copy file failed, ret=%{public}d", ret);
280 ret = static_cast<int32_t>(PasteboardError::COPY_FILE_ERROR);
281 }
282 dataParams->info->percentage = PERCENTAGE;
283 OnProgressNotify(dataParams);
284 g_recordSize = 0;
285 return ret;
286 }
287 } // namespace MiscServices
288 } // namespace OHOS