• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 #define LOG_TAG "UdmfCopyFile"
16 
17 #include "udmf_copy_file.h"
18 
19 #include <filesystem>
20 #include <sys/stat.h>
21 #include <unistd.h>
22 #include "copy/file_copy_manager.h"
23 #include "copy/file_size_utils.h"
24 #include "file_uri.h"
25 #include "logger.h"
26 #include "udmf_async_client.h"
27 
28 namespace OHOS {
29 namespace UDMF {
30 static constexpr const char* NETWORK_PARA = "?networkid=";
31 static constexpr int32_t PROGRESS_COPY_START = 20;
32 static constexpr int32_t PROGRESS_INCRE = 80;
33 static constexpr int32_t MAX_PROGRESS = 99;
34 static constexpr int32_t DFS_CANCEL_STATUS = 204;
35 
GetInstance()36 UdmfCopyFile &UdmfCopyFile::GetInstance()
37 {
38     static UdmfCopyFile udmfCopyFile;
39     return udmfCopyFile;
40 }
41 
Copy(std::unique_ptr<AsyncHelper> & asyncHelper)42 Status UdmfCopyFile::Copy(std::unique_ptr<AsyncHelper> &asyncHelper)
43 {
44     CopyContext context(asyncHelper);
45 
46     if (context.asyncHelper->progressQueue.IsCancel()) {
47         LOG_INFO(UDMF_CLIENT, "Copy file cancel");
48         return E_COPY_CANCELED;
49     }
50 
51     if (!IsDirectory(context.asyncHelper->destUri, false)) {
52         LOG_ERROR(UDMF_CLIENT, "DestUri is not directory.");
53         return E_FS_ERROR;
54     }
55 
56     for (const auto &record : context.asyncHelper->data->GetRecords()) {
57         if (!HandleRecord(record, context)) {
58             break;
59         }
60     }
61 
62     context.asyncHelper->data = context.processedData;
63     LOG_INFO(UDMF_CLIENT, "Copy end.");
64     return context.status;
65 }
66 
HandleRecord(const std::shared_ptr<UnifiedRecord> & record,CopyContext & context)67 bool UdmfCopyFile::HandleRecord(const std::shared_ptr<UnifiedRecord> &record, CopyContext &context)
68 {
69     std::string srcUri;
70     if (!record->HasFileType(srcUri)) {
71         context.processedData->AddRecord(record);
72         return true;
73     }
74     if (IsDirectory(srcUri, true)) {
75         LOG_ERROR(UDMF_CLIENT, "Source cannot be directory.");
76         context.status = E_COPY_FILE_FAILED;
77         return true;
78     }
79 
80     std::string destFileUri = ConstructDestUri(context.asyncHelper->destUri, srcUri);
81     if (context.asyncHelper->fileConflictOptions == FileConflictOptions::SKIP && IsFile(destFileUri, false)) {
82         LOG_INFO(UDMF_CLIENT, "File has existed, skip.");
83         return true;
84     }
85     return CopyFile(srcUri, destFileUri, record, context);
86 }
87 
CopyFile(const std::string & srcUri,const std::string & destFileUri,const std::shared_ptr<UnifiedRecord> & record,CopyContext & context)88 bool UdmfCopyFile::CopyFile(const std::string &srcUri, const std::string &destFileUri,
89                             const std::shared_ptr<UnifiedRecord> &record, CopyContext &context)
90 {
91     uint64_t fileSize = 0;
92     using ProcessCallBack = std::function<void(uint64_t processSize, uint64_t totalFileSize)>;
93     ProcessCallBack listener = [&](uint64_t processSize, uint64_t totalFileSize) {
94         fileSize = totalFileSize;
95         HandleProgress(srcUri, destFileUri, context, processSize);
96     };
97     auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Copy(srcUri, destFileUri, listener);
98     if (ret == DFS_CANCEL_STATUS) {
99         context.status = E_COPY_CANCELED;
100         return false;
101     } else if (ret != E_OK) {
102         LOG_ERROR(UDMF_CLIENT, "Copy failed. errno=%{public}d", ret);
103         context.status = E_COPY_FILE_FAILED;
104         return true;
105     }
106 
107     context.finishSize += fileSize;
108     record->SetFileUri(destFileUri);
109     context.processedData->AddRecord(record);
110     return true;
111 }
112 
HandleProgress(const std::string & srcUri,const std::string & destFileUri,CopyContext & context,uint64_t processSize)113 void UdmfCopyFile::HandleProgress(const std::string &srcUri, const std::string &destFileUri,
114     CopyContext &context, uint64_t processSize)
115 {
116     if (context.asyncHelper->progressQueue.IsCancel()) {
117         LOG_INFO(UDMF_CLIENT, "Cancel copy.");
118         std::thread([&]() {
119             auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Cancel(srcUri, destFileUri);
120             if (ret != E_OK) {
121                 LOG_ERROR(UDMF_CLIENT, "Cancel failed. errno=%{public}d", ret);
122                 context.status = E_COPY_FILE_FAILED;
123             }
124         }).detach();
125         return;
126     }
127 
128     context.totalSize = std::max(context.totalSize, uint64_t(1));
129     auto processNum = std::min(PROGRESS_COPY_START +
130         int32_t((context.finishSize + processSize) * PROGRESS_INCRE / context.totalSize), MAX_PROGRESS);
131     ProgressInfo progressInfo = { .progress = processNum, .errorCode = E_OK };
132     UdmfAsyncClient::GetInstance().CallProgress(context.asyncHelper, progressInfo, nullptr);
133 }
134 
ConstructDestUri(const std::string & destUri,const std::string & srcUri)135 std::string UdmfCopyFile::ConstructDestUri(const std::string &destUri, const std::string &srcUri)
136 {
137     std::string destFileUri = destUri;
138     if (destFileUri.back() != '/') {
139         destFileUri += '/';
140     }
141     destFileUri += GetFileName(srcUri);
142     return destFileUri;
143 }
144 
GetTotalSize(const std::vector<std::string> & uris)145 uint64_t UdmfCopyFile::GetTotalSize(const std::vector<std::string> &uris)
146 {
147     uint64_t totalSize = 0;
148     std::string srcUri;
149     for (const auto &srcUri : uris) {
150         if (IsFile(srcUri, true)) {
151             totalSize += GetFileSize(srcUri, true);
152         }
153     }
154     return totalSize;
155 }
156 
IsDirectory(const std::string & uri,bool isSource)157 bool UdmfCopyFile::IsDirectory(const std::string &uri, bool isSource)
158 {
159     bool isDir = false;
160     auto ret = Storage::DistributedFile::FileSizeUtils::IsDirectory(uri, isSource, isDir);
161     if (ret != E_OK) {
162         LOG_ERROR(UDMF_CLIENT, "Is dir failed. errno=%{public}d", ret);
163         return false;
164     }
165     return isDir;
166 }
167 
IsRemote(const std::string & uri)168 bool UdmfCopyFile::IsRemote(const std::string &uri)
169 {
170     return uri.find(NETWORK_PARA) != uri.npos;
171 }
172 
GetFileName(const std::string & path)173 std::string UdmfCopyFile::GetFileName(const std::string &path)
174 {
175     std::string realSrc = path;
176     if (IsRemote(path)) {
177         auto index = path.rfind("?", 0);
178         realSrc = path.substr(0, index);
179     }
180     std::filesystem::path filePath(realSrc);
181     return filePath.filename();
182 }
183 
IsFile(const std::string & uri,bool isSource)184 bool UdmfCopyFile::IsFile(const std::string &uri, bool isSource)
185 {
186     bool isDir = false;
187     auto ret = Storage::DistributedFile::FileSizeUtils::IsDirectory(uri, isSource, isDir);
188     if (ret != E_OK) {
189         LOG_ERROR(UDMF_CLIENT, "Is dir failed. errno=%{public}d", ret);
190         return false;
191     }
192     return !isDir;
193 }
194 
GetFileSize(const std::string & uri,bool isSource)195 uint64_t UdmfCopyFile::GetFileSize(const std::string &uri, bool isSource)
196 {
197     uint64_t size = 0;
198     auto ret = Storage::DistributedFile::FileSizeUtils::GetSize(uri, isSource, size);
199     if (ret != E_OK) {
200         LOG_ERROR(UDMF_CLIENT, "Get size failed. errno=%{public}d", ret);
201         return 0;
202     }
203     return size;
204 }
205 } // namespace UDMF
206 } // namespace OHOS