• 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 
16 #include "copy/file_copy_manager.h"
17 
18 #include <cstring>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <filesystem>
22 #include <limits>
23 #include <memory>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include "copy/distributed_file_fd_guard.h"
29 #include "copy/file_copy_listener.h"
30 #include "copy/file_size_utils.h"
31 #include "datashare_helper.h"
32 #include "dfs_error.h"
33 #include "distributed_file_daemon_proxy.h"
34 #include "file_uri.h"
35 #include "iremote_stub.h"
36 #include "sandbox_helper.h"
37 #include "utils_log.h"
38 
39 #undef LOG_DOMAIN
40 #undef LOG_TAG
41 #define LOG_DOMAIN 0xD001600
42 #define LOG_TAG "distributedfile_daemon"
43 
44 namespace OHOS {
45 namespace Storage {
46 namespace DistributedFile {
47 using namespace AppFileService;
48 using namespace FileManagement;
49 static const std::string FILE_PREFIX_NAME = "file://";
50 static const std::string NETWORK_PARA = "?networkid=";
51 static const std::string MEDIALIBRARY_DATA_URI = "datashare:///media";
52 static const std::string MEDIA = "media";
53 static constexpr size_t MAX_SIZE = 1024 * 1024 * 4;
54 std::shared_ptr<FileCopyManager> FileCopyManager::instance_ = nullptr;
55 
CheckPath(std::shared_ptr<FileInfos> & infos)56 static bool CheckPath(std::shared_ptr<FileInfos> &infos)
57 {
58     std::string destPath = infos->destPath;
59     if (infos->srcUriIsFile) {
60         auto pos = destPath.rfind("/");
61         if (pos == std::string::npos) {
62             return false;
63         }
64         destPath.resize(pos);
65     }
66     if (!(SandboxHelper::CheckValidPath(infos->srcPath) && SandboxHelper::CheckValidPath(destPath))) {
67         return false;
68     }
69     return true;
70 }
71 
GetInstance()72 std::shared_ptr<FileCopyManager> FileCopyManager::GetInstance()
73 {
74     static std::once_flag once;
75     std::call_once(once, []() {
76         FileCopyManager::instance_ = std::make_shared<FileCopyManager>();
77     });
78 
79     return instance_;
80 }
81 
Copy(const std::string & srcUri,const std::string & destUri,ProcessCallback & processCallback)82 int32_t FileCopyManager::Copy(const std::string &srcUri, const std::string &destUri, ProcessCallback &processCallback)
83 {
84     LOGE("FileCopyManager Copy start ");
85     if (srcUri.empty() || destUri.empty()) {
86         return E_NOENT;
87     }
88 
89     auto infos = std::make_shared<FileInfos>();
90     auto ret = CreateFileInfos(srcUri, destUri, infos);
91     if (ret != E_OK) {
92         return ret;
93     }
94 
95     if (IsRemoteUri(infos->srcUri)) {
96         ret = ExecRemote(infos, processCallback);
97         RemoveFileInfos(infos);
98         return ret;
99     }
100 
101     if (!CheckPath(infos)) {
102         LOGE("invalid srcPath : %{private}s, destPath: %{private}s", GetAnonyString(infos->srcPath).c_str(),
103             GetAnonyString(infos->destPath).c_str());
104         return E_NOENT;
105     }
106 
107     infos->localListener = FileCopyLocalListener::GetLocalListener(infos->srcPath,
108         infos->srcUriIsFile, processCallback);
109     infos->localListener->StartListener();
110     auto result = ExecLocal(infos);
111     RemoveFileInfos(infos);
112     infos->localListener->StopListener();
113 
114     if (result != E_OK) {
115         return result;
116     }
117     return infos->localListener->GetResult();
118 }
119 
ExecRemote(std::shared_ptr<FileInfos> infos,ProcessCallback & processCallback)120 int32_t FileCopyManager::ExecRemote(std::shared_ptr<FileInfos> infos, ProcessCallback &processCallback)
121 {
122     LOGI("ExecRemote Copy start ");
123     sptr<TransListener> transListener (new (std::nothrow) TransListener(infos->destUri, processCallback));
124     if (transListener == nullptr) {
125         LOGE("new trans listener failed");
126         return ENOMEM;
127     }
128     infos->transListener = transListener;
129 
130     auto networkId = transListener->GetNetworkIdFromUri(infos->srcUri);
131     auto distributedFileDaemonProxy = DistributedFileDaemonProxy::GetInstance();
132     if (distributedFileDaemonProxy == nullptr) {
133         LOGE("proxy is null");
134         return E_SA_LOAD_FAILED;
135     }
136     auto ret = distributedFileDaemonProxy->PrepareSession(infos->srcUri, infos->destUri,
137         networkId, transListener, transListener->hmdfsInfo_);
138     if (ret != E_OK) {
139         LOGE("PrepareSession failed, ret = %{public}d.", ret);
140         return ret;
141     }
142 
143     auto copyResult = transListener->WaitForCopyResult();
144     if (copyResult == FAILED) {
145         return transListener->GetErrCode();
146     }
147     return transListener->CopyToSandBox(infos->srcUri);
148 }
149 
Cancel()150 int32_t FileCopyManager::Cancel()
151 {
152     LOGI("Cancel all Copy");
153     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
154     for (auto &item : FileInfosVec_) {
155         item->needCancel.store(true);
156         if (item->transListener != nullptr) {
157             item->transListener->Cancel();
158         }
159         DeleteResFile(item);
160     }
161     FileInfosVec_.clear();
162     return E_OK;
163 }
164 
Cancel(const std::string & srcUri,const std::string & destUri)165 int32_t FileCopyManager::Cancel(const std::string &srcUri, const std::string &destUri)
166 {
167     LOGI("Cancel Copy");
168     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
169     int32_t ret = 0;
170     for (auto item = FileInfosVec_.begin(); item != FileInfosVec_.end();) {
171         if ((*item)->srcUri != srcUri || (*item)->destUri != destUri) {
172             ++item;
173             continue;
174         }
175         (*item)->needCancel.store(true);
176         if ((*item)->transListener != nullptr) {
177             ret = (*item)->transListener->Cancel();
178         }
179         DeleteResFile(*item);
180         item = FileInfosVec_.erase(item);
181         return ret;
182     }
183     return E_OK;
184 }
185 
DeleteResFile(std::shared_ptr<FileInfos> infos)186 void FileCopyManager::DeleteResFile(std::shared_ptr<FileInfos> infos)
187 {
188     std::error_code errCode;
189     //delete files in remote cancel
190     if (infos->transListener != nullptr) {
191         if (std::filesystem::exists(infos->destPath, errCode)) {
192             std::filesystem::remove(infos->destPath, errCode);
193         }
194         return;
195     }
196 
197     //delete files&dirs in local cancel
198     auto filePaths = infos->localListener->GetFilePath();
199     for (auto path : filePaths) {
200         if (!std::filesystem::exists(path, errCode)) {
201             LOGE("Failed to find the file, errcode %{public}d", errCode.value());
202             continue;
203         }
204         std::filesystem::remove(path, errCode);
205     }
206 
207     std::lock_guard<std::mutex> lock(infos->subDirsMutex);
208     for (auto subDir : infos->subDirs) {
209         if (!std::filesystem::exists(subDir, errCode)) {
210             LOGE("Failed to find the dir, errcode %{public}d", errCode.value());
211             continue;
212         }
213         std::filesystem::remove(subDir, errCode);
214     }
215 }
216 
ExecLocal(std::shared_ptr<FileInfos> infos)217 int32_t FileCopyManager::ExecLocal(std::shared_ptr<FileInfos> infos)
218 {
219     LOGI("start ExecLocal");
220     // 文件到文件, 文件到目录的形式由上层改写为文件到文件的形式
221     if (infos->srcUriIsFile) {
222         if (infos->srcPath == infos->destPath) {
223             LOGE("The src and dest is same");
224             return E_OK;
225         }
226         int32_t ret = CheckOrCreatePath(infos->destPath);
227         if (ret != E_OK) {
228             LOGE("check or create fail, error code is %{public}d", ret);
229             return ret;
230         }
231         infos->localListener->AddListenerFile(infos->destPath, IN_MODIFY);
232         return CopyFile(infos->srcPath, infos->destPath, infos);
233     }
234 
235     bool destIsDirectory;
236     auto ret = FileSizeUtils::IsDirectory(infos->destUri, false, destIsDirectory);
237     if (ret != E_OK) {
238         LOGE("destPath: %{public}s not find, error=%{public}d", infos->destPath.c_str(), ret);
239         return ret;
240     }
241     if (destIsDirectory) {
242         if (infos->srcPath.back() != '/') {
243             infos->srcPath += '/';
244         }
245         if (infos->destPath.back() != '/') {
246             infos->destPath += '/';
247         }
248         // copyDir
249         return CopyDirFunc(infos->srcPath, infos->destPath, infos);
250     }
251     LOGI("ExecLocal not support this srcUri and destUri");
252     return E_NOENT;
253 }
254 
CopyFile(const std::string & src,const std::string & dest,std::shared_ptr<FileInfos> infos)255 int32_t FileCopyManager::CopyFile(const std::string &src, const std::string &dest, std::shared_ptr<FileInfos> infos)
256 {
257     LOGI("src = %{private}s, dest = %{private}s", src.c_str(), dest.c_str());
258     infos->localListener->AddFile(dest);
259     int32_t srcFd = -1;
260     int32_t ret = OpenSrcFile(src, infos, srcFd);
261     if (srcFd < 0) {
262         return ret;
263     }
264     auto destFd = open(dest.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
265     if (destFd < 0) {
266         LOGE("Error opening dest file descriptor. errno = %{public}d", errno);
267         close(srcFd);
268         return errno;
269     }
270     std::shared_ptr<FDGuard> srcFdg = std::make_shared<FDGuard>(srcFd, true);
271     std::shared_ptr<FDGuard> destFdg = std::make_shared<FDGuard>(destFd, true);
272     if (srcFdg == nullptr || destFdg == nullptr) {
273         LOGE("Failed to request heap memory.");
274         close(srcFd);
275         close(destFd);
276         return -1;
277     }
278     return SendFileCore(srcFdg, destFdg, infos);
279 }
280 
fs_req_cleanup(uv_fs_t * req)281 void fs_req_cleanup(uv_fs_t* req)
282 {
283     uv_fs_req_cleanup(req);
284     if (req) {
285         delete req;
286         req = nullptr;
287     }
288 }
289 
SendFileCore(std::shared_ptr<FDGuard> srcFdg,std::shared_ptr<FDGuard> destFdg,std::shared_ptr<FileInfos> infos)290 int32_t FileCopyManager::SendFileCore(std::shared_ptr<FDGuard> srcFdg,
291     std::shared_ptr<FDGuard> destFdg, std::shared_ptr<FileInfos> infos)
292 {
293     std::unique_ptr<uv_fs_t, decltype(fs_req_cleanup)*> sendFileReq = {
294         new (std::nothrow) uv_fs_t, fs_req_cleanup };
295     if (sendFileReq == nullptr) {
296         LOGE("Failed to request heap memory.");
297         return -1;
298     }
299     int64_t offset = 0;
300     struct stat srcStat{};
301     if (fstat(srcFdg->GetFD(), &srcStat) < 0) {
302         LOGE("Failed to get stat of file by fd: %{public}d ,errno = %{public}d", srcFdg->GetFD(), errno);
303         return errno;
304     }
305     int32_t ret = 0;
306     int64_t size = static_cast<int64_t>(srcStat.st_size);
307 
308     while (size >= 0) {
309         ret = uv_fs_sendfile(nullptr, sendFileReq.get(), destFdg->GetFD(), srcFdg->GetFD(),
310             offset, MAX_SIZE, nullptr);
311         if (ret < 0) {
312             LOGE("Failed to sendfile by errno : %{public}d", errno);
313             return errno;
314         }
315 
316         if (infos->needCancel.load()) {
317             LOGE("need cancel");
318             return FileManagement::E_DFS_CANCEL_SUCCESS; // 204
319         }
320 
321         offset += static_cast<int64_t>(ret);
322         size -= static_cast<int64_t>(ret);
323         if (ret == 0) {
324             break;
325         }
326     }
327 
328     if (size != 0) {
329         LOGE("The execution of the sendfile task was terminated, remaining file size %{public}" PRIu64, size);
330         return E_OK; // EIO
331     }
332     return E_OK;
333 }
334 
CopyDirFunc(const std::string & src,const std::string & dest,std::shared_ptr<FileInfos> infos)335 int32_t FileCopyManager::CopyDirFunc(const std::string &src, const std::string &dest, std::shared_ptr<FileInfos> infos)
336 {
337     LOGI("CopyDirFunc in, src = %{private}s, dest = %{private}s", src.c_str(), dest.c_str());
338     size_t found = dest.find(src);
339     if (found != std::string::npos && found == 0) {
340         LOGE("not support copy src to dest");
341         return -1;
342     }
343 
344     // 获取src目录的目录名称
345     std::filesystem::path srcPath = std::filesystem::u8path(src);
346     std::string dirName;
347     if (srcPath.has_parent_path()) {
348         dirName = srcPath.parent_path().filename();
349     }
350 
351     // 构造要拷贝到的路径
352     std::string destStr = dest + "/" + dirName;
353     return CopySubDir(src, destStr, infos);
354 }
355 
CopySubDir(const std::string & srcPath,const std::string & destPath,std::shared_ptr<FileInfos> infos)356 int32_t FileCopyManager::CopySubDir(const std::string &srcPath,
357     const std::string &destPath, std::shared_ptr<FileInfos> infos)
358 {
359     std::error_code errCode;
360     if (!std::filesystem::exists(destPath, errCode) && errCode.value() == E_OK) {
361         int res = MakeDir(destPath);
362         if (res != E_OK) {
363             LOGE("Failed to mkdir");
364             return res;
365         }
366     } else if (errCode.value() != E_OK) {
367         LOGE("fs exists fail, errcode is %{public}d", errCode.value());
368         return errCode.value();
369     }
370     {
371         std::lock_guard<std::mutex> lock(infos->subDirsMutex);
372         infos->subDirs.insert(destPath);
373     }
374     infos->localListener->AddListenerFile(destPath, IN_MODIFY);
375     return RecurCopyDir(srcPath, destPath, infos);
376 }
377 
RecurCopyDir(const std::string & srcPath,const std::string & destPath,std::shared_ptr<FileInfos> infos)378 int32_t FileCopyManager::RecurCopyDir(const std::string &srcPath,
379     const std::string &destPath, std::shared_ptr<FileInfos> infos)
380 {
381     auto pNameList = FileSizeUtils::GetDirNameList(srcPath);
382     if (pNameList == nullptr) {
383         return ENOMEM;
384     }
385     for (int i = 0; i < pNameList->direntNum; i++) {
386         std::string src = srcPath + '/' + std::string((pNameList->namelist[i])->d_name);
387         std::string dest = destPath + '/' + std::string((pNameList->namelist[i])->d_name);
388         if ((pNameList->namelist[i])->d_type == DT_LNK) {
389             continue;
390         }
391         int ret = E_OK;
392         if ((pNameList->namelist[i])->d_type == DT_DIR) {
393             ret = CopySubDir(src, dest, infos);
394         } else {
395             ret = CopyFile(src, dest, infos);
396         }
397         if (ret != E_OK) {
398             return ret;
399         }
400     }
401     return E_OK;
402 }
403 
AddFileInfos(std::shared_ptr<FileInfos> infos)404 void FileCopyManager::AddFileInfos(std::shared_ptr<FileInfos> infos)
405 {
406     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
407     FileInfosVec_.push_back(infos);
408 }
409 
RemoveFileInfos(std::shared_ptr<FileInfos> infos)410 void FileCopyManager::RemoveFileInfos(std::shared_ptr<FileInfos> infos)
411 {
412     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
413     for (auto it = FileInfosVec_.begin(); it != FileInfosVec_.end();) {
414         if ((*it)->srcUri == infos->srcUri && (*it)->destUri == infos->destUri) {
415             it = FileInfosVec_.erase(it);
416         } else {
417             ++it;
418         }
419     }
420 }
421 
CreateFileInfos(const std::string & srcUri,const std::string & destUri,std::shared_ptr<FileInfos> & infos)422 int32_t FileCopyManager::CreateFileInfos(const std::string &srcUri,
423     const std::string &destUri, std::shared_ptr<FileInfos> &infos)
424 {
425     infos->srcUri = srcUri;
426     infos->destUri = destUri;
427     infos->srcPath = FileSizeUtils::GetPathFromUri(srcUri, true);
428     infos->destPath = FileSizeUtils::GetPathFromUri(destUri, false);
429 
430     bool isDirectory;
431     auto ret = FileSizeUtils::IsDirectory(infos->srcUri, true, isDirectory);
432     if (ret != E_OK) {
433         LOGE("srcPath: %{public}s not find, err=%{public}d", infos->srcPath.c_str(), ret);
434         return ret;
435     }
436     infos->srcUriIsFile = IsMediaUri(infos->srcUri) || !isDirectory;
437     AddFileInfos(infos);
438     return E_OK;
439 }
440 
GetModeFromFlags(unsigned int flags)441 std::string GetModeFromFlags(unsigned int flags)
442 {
443     const std::string readMode = "r";
444     const std::string writeMode = "w";
445     const std::string appendMode = "a";
446     const std::string truncMode = "t";
447     std::string mode = readMode;
448     mode += (((flags & O_RDWR) == O_RDWR) ? writeMode : "");
449     mode = (((flags & O_WRONLY) == O_WRONLY) ? writeMode : mode);
450     if (mode != readMode) {
451         mode += ((flags & O_TRUNC) ? truncMode : "");
452         mode += ((flags & O_APPEND) ? appendMode : "");
453     }
454     return mode;
455 }
456 
OpenSrcFile(const std::string & srcPth,std::shared_ptr<FileInfos> infos,int32_t & srcFd)457 int32_t FileCopyManager::OpenSrcFile(const std::string &srcPth, std::shared_ptr<FileInfos> infos, int32_t &srcFd)
458 {
459     Uri uri(infos->srcUri);
460 
461     if (uri.GetAuthority() == MEDIA) {
462         std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
463         sptr<FileIoToken> remote = new (std::nothrow) IRemoteStub<FileIoToken>();
464         if (!remote) {
465             LOGE("Failed to get remote object");
466             return -1;
467         }
468         dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI);
469         if (!dataShareHelper) {
470             LOGE("Failed to connect to datashare");
471             return -1;
472         }
473         srcFd = dataShareHelper->OpenFile(uri, GetModeFromFlags(O_RDONLY));
474         if (srcFd < 0) {
475             LOGE("Open media uri by data share fail. ret = %{public}d", srcFd);
476             return -1;
477         }
478     } else {
479         srcFd = open(srcPth.c_str(), O_RDONLY);
480         if (srcFd < 0) {
481             LOGE("Error opening src file descriptor. errno = %{public}d", errno);
482             return errno;
483         }
484     }
485     return 0;
486 }
487 
MakeDir(const std::string & path)488 int FileCopyManager::MakeDir(const std::string &path)
489 {
490     std::filesystem::path destDir(path);
491     std::error_code errCode;
492     if (!std::filesystem::create_directory(destDir, errCode)) {
493         LOGE("Failed to create directory, error code: %{public}d", errCode.value());
494         return errCode.value();
495     }
496     return E_OK;
497 }
498 
IsRemoteUri(const std::string & uri)499 bool FileCopyManager::IsRemoteUri(const std::string &uri)
500 {
501     // NETWORK_PARA
502     return uri.find(NETWORK_PARA) != uri.npos;
503 }
504 
IsMediaUri(const std::string & uriPath)505 bool FileCopyManager::IsMediaUri(const std::string &uriPath)
506 {
507     Uri uri(uriPath);
508     std::string bundleName = uri.GetAuthority();
509     return bundleName == MEDIA;
510 }
511 
CheckOrCreatePath(const std::string & destPath)512 int32_t FileCopyManager::CheckOrCreatePath(const std::string &destPath)
513 {
514     std::error_code errCode;
515     if (!std::filesystem::exists(destPath, errCode) && errCode.value() == E_OK) {
516         LOGI("destPath not exist");
517         auto file = open(destPath.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
518         if (file < 0) {
519             LOGE("Error opening file descriptor. errno = %{public}d", errno);
520             return errno;
521         }
522         close(file);
523     } else if (errCode.value() != 0) {
524         return errCode.value();
525     }
526     return E_OK;
527 }
528 } // namespace DistributedFile
529 } // namespace Storage
530 } // namespace OHOS
531