• 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 
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