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