• 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 #include "unified_html_record_process.h"
28 
29 namespace OHOS {
30 namespace UDMF {
31 static constexpr const char* NETWORK_PARA = "?networkid=";
32 static constexpr int32_t PROGRESS_COPY_START = 20;
33 static constexpr int32_t PROGRESS_INCRE = 80;
34 static constexpr int32_t MAX_PROGRESS = 99;
35 static constexpr int32_t DFS_CANCEL_STATUS = 204;
36 
GetInstance()37 UdmfCopyFile &UdmfCopyFile::GetInstance()
38 {
39     static UdmfCopyFile udmfCopyFile;
40     return udmfCopyFile;
41 }
42 
Copy(std::unique_ptr<AsyncHelper> & asyncHelper)43 Status UdmfCopyFile::Copy(std::unique_ptr<AsyncHelper> &asyncHelper)
44 {
45     CopyContext context(asyncHelper);
46 
47     if (context.asyncHelper->progressQueue.IsCancel()) {
48         LOG_INFO(UDMF_CLIENT, "Copy file cancel");
49         return E_COPY_CANCELED;
50     }
51 
52     if (!IsDirectory(context.asyncHelper->destUri, false)) {
53         LOG_ERROR(UDMF_CLIENT, "DestUri is not directory.");
54         return E_FS_ERROR;
55     }
56 
57     for (const auto &record : context.asyncHelper->data->GetRecords()) {
58         if (!HandleRecord(record, context)) {
59             break;
60         }
61     }
62 
63     HandleUris(context);
64     context.asyncHelper->data = context.processedData;
65     LOG_INFO(UDMF_CLIENT, "Copy end.");
66     return context.status;
67 }
68 
HandleUris(CopyContext & context)69 void UdmfCopyFile::HandleUris(CopyContext &context)
70 {
71     for (const auto &record : context.asyncHelper->data->GetRecords()) {
72         if (record == nullptr) {
73             continue;
74         }
75         for (auto &uri : record->GetUris()) {
76             std::string srcUri = uri.dfsUri.empty() ? uri.authUri : uri.dfsUri;
77             if (IsDirectory(srcUri, true)) {
78                 LOG_ERROR(UDMF_CLIENT, "Source cannot be directory.");
79                 context.status = E_COPY_FILE_FAILED;
80                 continue;
81             }
82             std::string destUri = ConstructDestUri(context.asyncHelper->destUri, srcUri);
83             if (context.asyncHelper->fileConflictOptions == FileConflictOptions::SKIP && IsFile(destUri, false)) {
84                 LOG_INFO(UDMF_CLIENT, "File has existed, skip.");
85                 continue;
86             }
87             if (!CopyFile(srcUri, destUri, record, context)) {
88                 LOG_ERROR(UDMF_CLIENT, "copy cancel");
89                 return;
90             }
91             UpdateUriInfo(destUri, record, uri);
92         }
93     }
94     UnifiedHtmlRecordProcess::RebuildHtmlRecord(*(context.asyncHelper->data));
95 }
96 
UpdateUriInfo(const std::string & destUri,const std::shared_ptr<UnifiedRecord> & record,UriInfo uri)97 void UdmfCopyFile::UpdateUriInfo(const std::string &destUri, const std::shared_ptr<UnifiedRecord> &record,
98     UriInfo uri)
99 {
100     record->ComputeUris([&destUri, &uri] (UriInfo &uriInfo) {
101         if (uri.dfsUri.empty()) {
102             if (uri.authUri == uriInfo.authUri) {
103                 uriInfo.dfsUri = destUri;
104             }
105         } else {
106             if (uri.dfsUri == uriInfo.dfsUri) {
107                 uriInfo.dfsUri = destUri;
108             }
109         }
110         return true;
111     });
112 }
113 
HandleRecord(const std::shared_ptr<UnifiedRecord> & record,CopyContext & context)114 bool UdmfCopyFile::HandleRecord(const std::shared_ptr<UnifiedRecord> &record, CopyContext &context)
115 {
116     std::string srcUri;
117     if (!record->HasFileType(srcUri) && !record->HasType(UtdUtils::GetUtdIdFromUtdEnum(UDType::HTML))) {
118         context.processedData->AddRecord(record);
119         return true;
120     }
121     if (IsDirectory(srcUri, true)) {
122         LOG_ERROR(UDMF_CLIENT, "Source cannot be directory.");
123         context.status = E_COPY_FILE_FAILED;
124         return true;
125     }
126 
127     std::string destFileUri = ConstructDestUri(context.asyncHelper->destUri, srcUri);
128     if (context.asyncHelper->fileConflictOptions == FileConflictOptions::SKIP && IsFile(destFileUri, false)) {
129         LOG_INFO(UDMF_CLIENT, "File has existed, skip.");
130         return true;
131     }
132     return CopyFile(srcUri, destFileUri, record, context);
133 }
134 
CopyFile(const std::string & srcUri,const std::string & destFileUri,const std::shared_ptr<UnifiedRecord> & record,CopyContext & context)135 bool UdmfCopyFile::CopyFile(const std::string &srcUri, const std::string &destFileUri,
136                             const std::shared_ptr<UnifiedRecord> &record, CopyContext &context)
137 {
138     uint64_t fileSize = 0;
139     using ProcessCallBack = std::function<void(uint64_t processSize, uint64_t totalFileSize)>;
140     ProcessCallBack listener = [&](uint64_t processSize, uint64_t totalFileSize) {
141         fileSize = totalFileSize;
142         HandleProgress(srcUri, destFileUri, context, processSize);
143     };
144     auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Copy(srcUri, destFileUri, listener);
145     if (ret == DFS_CANCEL_STATUS) {
146         context.status = E_COPY_CANCELED;
147         return false;
148     } else if (ret != E_OK) {
149         LOG_ERROR(UDMF_CLIENT, "Copy failed. errno=%{public}d", ret);
150         context.status = E_COPY_FILE_FAILED;
151         return true;
152     }
153 
154     context.finishSize += fileSize;
155     record->SetFileUri(destFileUri);
156     context.processedData->AddRecord(record);
157     return true;
158 }
159 
HandleProgress(const std::string & srcUri,const std::string & destFileUri,CopyContext & context,uint64_t processSize)160 void UdmfCopyFile::HandleProgress(const std::string &srcUri, const std::string &destFileUri,
161     CopyContext &context, uint64_t processSize)
162 {
163     if (context.asyncHelper->progressQueue.IsCancel()) {
164         LOG_INFO(UDMF_CLIENT, "Cancel copy.");
165         std::thread([&]() {
166             auto ret = Storage::DistributedFile::FileCopyManager::GetInstance()->Cancel(srcUri, destFileUri);
167             if (ret != E_OK) {
168                 LOG_ERROR(UDMF_CLIENT, "Cancel failed. errno=%{public}d", ret);
169                 context.status = E_COPY_FILE_FAILED;
170             }
171         }).detach();
172         return;
173     }
174 
175     context.totalSize = std::max(context.totalSize, uint64_t(1));
176     auto processNum = std::min(PROGRESS_COPY_START +
177         int32_t((context.finishSize + processSize) * PROGRESS_INCRE / context.totalSize), MAX_PROGRESS);
178     ProgressInfo progressInfo = { .progress = processNum, .errorCode = E_OK };
179     UdmfAsyncClient::GetInstance().CallProgress(context.asyncHelper, progressInfo, nullptr);
180 }
181 
ConstructDestUri(const std::string & destUri,const std::string & srcUri)182 std::string UdmfCopyFile::ConstructDestUri(const std::string &destUri, const std::string &srcUri)
183 {
184     std::string destFileUri = destUri;
185     if (destFileUri.back() != '/') {
186         destFileUri += '/';
187     }
188     destFileUri += GetFileName(srcUri);
189     return destFileUri;
190 }
191 
GetTotalSize(const std::vector<std::string> & uris)192 uint64_t UdmfCopyFile::GetTotalSize(const std::vector<std::string> &uris)
193 {
194     uint64_t totalSize = 0;
195     std::string srcUri;
196     for (const auto &srcUri : uris) {
197         if (IsFile(srcUri, true)) {
198             totalSize += GetFileSize(srcUri, true);
199         }
200     }
201     return totalSize;
202 }
203 
IsDirectory(const std::string & uri,bool isSource)204 bool UdmfCopyFile::IsDirectory(const std::string &uri, bool isSource)
205 {
206     bool isDir = false;
207     auto ret = Storage::DistributedFile::FileSizeUtils::IsDirectory(uri, isSource, isDir);
208     if (ret != E_OK) {
209         LOG_ERROR(UDMF_CLIENT, "Is dir failed. errno=%{public}d", ret);
210         return false;
211     }
212     return isDir;
213 }
214 
IsRemote(const std::string & uri)215 bool UdmfCopyFile::IsRemote(const std::string &uri)
216 {
217     return uri.find(NETWORK_PARA) != uri.npos;
218 }
219 
GetFileName(const std::string & path)220 std::string UdmfCopyFile::GetFileName(const std::string &path)
221 {
222     std::string realSrc = path;
223     if (IsRemote(path)) {
224         size_t index = path.rfind("?", 0);
225         realSrc = path.substr(0, index);
226     }
227     std::filesystem::path filePath(realSrc);
228     return filePath.filename();
229 }
230 
IsFile(const std::string & uri,bool isSource)231 bool UdmfCopyFile::IsFile(const std::string &uri, bool isSource)
232 {
233     bool isDir = false;
234     auto ret = Storage::DistributedFile::FileSizeUtils::IsDirectory(uri, isSource, isDir);
235     if (ret != E_OK) {
236         LOG_ERROR(UDMF_CLIENT, "Is dir failed. errno=%{public}d", ret);
237         return false;
238     }
239     return !isDir;
240 }
241 
GetFileSize(const std::string & uri,bool isSource)242 uint64_t UdmfCopyFile::GetFileSize(const std::string &uri, bool isSource)
243 {
244     uint64_t size = 0;
245     auto ret = Storage::DistributedFile::FileSizeUtils::GetSize(uri, isSource, size);
246     if (ret != E_OK) {
247         LOG_ERROR(UDMF_CLIENT, "Get size failed. errno=%{public}d", ret);
248         return 0;
249     }
250     return size;
251 }
252 } // namespace UDMF
253 } // namespace OHOS