• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 std::atomic_bool PasteBoardCopyFile::canCancel_{ true };
37 
GetInstance()38 PasteBoardCopyFile &PasteBoardCopyFile::GetInstance()
39 {
40     static PasteBoardCopyFile instance;
41     return instance;
42 }
43 
IsDirectory(const std::string & path)44 bool PasteBoardCopyFile::IsDirectory(const std::string &path)
45 {
46     struct stat buf {};
47     int ret = stat(path.c_str(), &buf);
48     if (ret == -1) {
49         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Stat failed. errno=%{public}d", errno);
50         return false;
51     }
52     return (buf.st_mode & S_IFMT) == S_IFDIR;
53 }
54 
IsFile(const std::string & path)55 bool PasteBoardCopyFile::IsFile(const std::string &path)
56 {
57     struct stat buf {};
58     int ret = stat(path.c_str(), &buf);
59     if (ret == -1) {
60         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Stat failed. errno = %{public}d", errno);
61         return false;
62     }
63     return (buf.st_mode & S_IFMT) == S_IFREG;
64 }
65 
OnProgressNotify(std::shared_ptr<GetDataParams> params)66 void PasteBoardCopyFile::OnProgressNotify(std::shared_ptr<GetDataParams> params)
67 {
68     if (params == nullptr) {
69         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "params is null!");
70         return;
71     }
72 
73     if (params->info == nullptr) {
74         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "params->info is null!");
75         return;
76     }
77 
78     if (params->info->percentage > PERCENTAGE) {
79         params->info->percentage = PERCENTAGE;
80     }
81     params->info->percentage = static_cast<int32_t>(params->info->percentage * FILE_PERCENTAGE + BEGIN_PERCENTAGE);
82     params->info->percentage = std::abs(params->info->percentage);
83     params->info->percentage = std::max(params->info->percentage, 0);
84     if (progressListener_.ProgressNotify != nullptr) {
85         progressListener_.ProgressNotify(params);
86     } else {
87         PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "ProgressNotify is nullptr.");
88     }
89 }
90 
GetRealPath(const std::string & path)91 std::string PasteBoardCopyFile::GetRealPath(const std::string& path)
92 {
93     std::filesystem::path tempPath(path);
94     std::filesystem::path realPath{};
95     for (const auto& component : tempPath) {
96         if (component == ".") {
97             continue;
98         } else if (component == "..") {
99             realPath = realPath.parent_path();
100         } else {
101             realPath /= component;
102         }
103     }
104     return realPath.string();
105 }
106 
IsRemoteUri(const std::string & uri)107 bool PasteBoardCopyFile::IsRemoteUri(const std::string &uri)
108 {
109     return uri.find(NETWORK_PARA) != uri.npos;
110 }
111 
CheckCopyParam(PasteData & pasteData,std::shared_ptr<GetDataParams> dataParams)112 int32_t PasteBoardCopyFile::CheckCopyParam(PasteData &pasteData, std::shared_ptr<GetDataParams> dataParams)
113 {
114     if (dataParams == nullptr) {
115         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Invalid dataParams");
116         return static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR);
117     }
118     g_recordSize = (int32_t)pasteData.GetRecordCount();
119     if (g_recordSize <= 0) {
120         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Invalid records size");
121         return static_cast<int32_t>(PasteboardError::INVALID_PARAM_ERROR);
122     }
123     return static_cast<int32_t>(PasteboardError::E_OK);
124 }
125 
InitCopyInfo(const std::string srcUri,std::shared_ptr<GetDataParams> dataParams,std::shared_ptr<CopyInfo> copyInfo,int32_t index)126 int32_t PasteBoardCopyFile::InitCopyInfo(const std::string srcUri, std::shared_ptr<GetDataParams> dataParams,
127     std::shared_ptr<CopyInfo> copyInfo, int32_t index)
128 {
129     copyInfo->srcUri = srcUri;
130     copyInfo->destUri = dataParams->destUri;
131     FileUri srcFileUri(copyInfo->srcUri);
132     copyInfo->srcPath = srcFileUri.GetRealPath();
133     FileUri destFileUri(copyInfo->destUri);
134     copyInfo->destPath = destFileUri.GetPath();
135     copyInfo->srcPath = GetRealPath(copyInfo->srcPath);
136     copyInfo->destPath = GetRealPath(copyInfo->destPath);
137     std::string realSrc = copyInfo->srcPath;
138     if (IsRemoteUri(copyInfo->srcUri)) {
139         uint32_t index = copyInfo->srcPath.rfind("?", 0);
140         realSrc = copyInfo->srcPath.substr(0, index);
141     }
142     if (IsDirectory(copyInfo->destPath)) {
143         std::filesystem::path filePath(realSrc);
144         auto fileName = filePath.filename();
145         if (copyInfo->destUri.back() != '/') {
146             copyInfo->destUri += '/';
147         }
148         copyInfo->destUri += fileName.string();
149         FileUri realDest(copyInfo->destUri);
150         copyInfo->destPath = realDest.GetPath();
151         copyInfo->destPath = GetRealPath(copyInfo->destPath);
152     }
153     std::error_code errCode;
154     if (std::filesystem::exists(copyInfo->destPath, errCode) && errCode.value() == ERRNO_NOERR &&
155         dataParams->fileConflictOption == FILE_SKIP) {
156         PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "File has existed.");
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->GetUriV0();
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 (!ShouldKeepRecord(ret, copyInfo->destUri, record)) {
208             pasteData.RemoveRecordAt(index);
209         } else {
210             index++;
211         }
212         PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "DFS copy ret: %{public}d", ret);
213     }
214     return (ret == ERRNO_NOERR || ret == DFS_CANCEL_SUCCESS) ? static_cast<int32_t>(PasteboardError::E_OK) : ret;
215 }
216 
ShouldKeepRecord(int32_t & ret,const std::string & destUri,std::shared_ptr<PasteDataRecord> record)217 bool PasteBoardCopyFile::ShouldKeepRecord(
218     int32_t &ret, const std::string &destUri, std::shared_ptr<PasteDataRecord> record)
219 {
220     if (record == nullptr) {
221         return false;
222     }
223     if ((ret == static_cast<int32_t>(PasteboardError::E_OK) || ret == ERRNO_NOERR) &&
224         !ProgressSignalClient::GetInstance().CheckCancelIfNeed()) {
225         auto sharedUri = std::make_shared<OHOS::Uri>(destUri);
226         record->SetUri(sharedUri);
227         record->SetConvertUri("");
228         return true;
229     } else if (record->GetFrom() > 0 && record->GetRecordId() != record->GetFrom() &&
230         !ProgressSignalClient::GetInstance().CheckCancelIfNeed()) {
231         ret = ERRNO_NOERR;
232         return true;
233     } else {
234         return false;
235     }
236 }
237 
HandleProgress(int32_t index,const CopyInfo & info,uint64_t processSize,uint64_t totalSize,std::shared_ptr<GetDataParams> dataParams)238 void PasteBoardCopyFile::HandleProgress(int32_t index, const CopyInfo &info, uint64_t processSize, uint64_t totalSize,
239     std::shared_ptr<GetDataParams> dataParams)
240 {
241     if (dataParams == nullptr) {
242         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "dataParams is nullptr.");
243         return;
244     }
245 
246     if (dataParams->info == nullptr) {
247         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "dataParams->info is nullptr.");
248         return;
249     }
250 
251     if (index < 1 || totalSize == 0) {
252         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "invalid parameter");
253         return;
254     }
255 
256     if (g_recordSize == 0) {
257         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "no record");
258         return;
259     }
260 
261     if (ProgressSignalClient::GetInstance().CheckCancelIfNeed() && canCancel_.load()) {
262         PASTEBOARD_HILOGI(PASTEBOARD_MODULE_CLIENT, "Cancel copy.");
263         std::thread([info]() {
264             canCancel_.store(false);
265             auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Cancel(info.srcUri, info.destUri);
266             if (ret != ERRNO_NOERR) {
267                 canCancel_.store(true);
268                 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Cancel failed. errno=%{public}d", ret);
269             }
270         }).detach();
271         return;
272     }
273 
274     int32_t percentage = (int32_t)((PERCENTAGE * processSize) / totalSize);
275     int32_t totalProgress = ((index - 1) * PERCENTAGE + percentage) / g_recordSize;
276     dataParams->info->percentage = totalProgress;
277 
278     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "process record index:%{public}d/%{public}d, progress=%{public}d",
279         index, g_recordSize, totalProgress);
280     OnProgressNotify(dataParams);
281 }
282 
CopyPasteData(PasteData & pasteData,std::shared_ptr<GetDataParams> dataParams)283 int32_t PasteBoardCopyFile::CopyPasteData(PasteData &pasteData, std::shared_ptr<GetDataParams> dataParams)
284 {
285     g_recordSize = 0;
286     canCancel_.store(true);
287     int32_t ret = CheckCopyParam(pasteData, dataParams);
288     if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
289         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "Invalid copy params");
290         g_recordSize = 0;
291         return ret;
292     }
293     ret = CopyFileData(pasteData, dataParams);
294     if (ret != static_cast<int32_t>(PasteboardError::E_OK)) {
295         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_CLIENT, "copy file failed, ret=%{public}d", ret);
296         ret = static_cast<int32_t>(PasteboardError::COPY_FILE_ERROR);
297     }
298     dataParams->info->percentage = PERCENTAGE;
299     OnProgressNotify(dataParams);
300     g_recordSize = 0;
301     return ret;
302 }
303 } // namespace MiscServices
304 } // namespace OHOS