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