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 "copy.h" 17#include <fcntl.h> 18#include <filesystem> 19#include <poll.h> 20#include <sys/eventfd.h> 21#include <sys/inotify.h> 22#include <sys/prctl.h> 23#include <sys/stat.h> 24#include <sys/types.h> 25#include <thread> 26#include "datashare_helper.h" 27#include "file_uri.h" 28#include "file_utils.h" 29#include "iservice_registry.h" 30#include "translistener.h" 31 32namespace OHOS { 33namespace CJSystemapi { 34using namespace FileFs; 35namespace fs = std::filesystem; 36const std::string NETWORK_PARA = "?networkid="; 37const std::string MEDIALIBRARY_DATA_URI = "datashare:///media"; 38constexpr int DISMATCH = 0; 39constexpr int MATCH = 1; 40constexpr int BUF_SIZE = 1024; 41constexpr size_t MAX_SIZE = 1024 * 1024 * 128; 42constexpr std::chrono::milliseconds NOTIFY_PROGRESS_DELAY(300); 43std::recursive_mutex CopyImpl::mutex_; 44std::map<FileInfos, std::shared_ptr<CjCallbackObject>> CopyImpl::cjCbMap_; 45 46static int OpenSrcFile(const std::string &srcPth, std::shared_ptr<FileInfos> infos, int32_t &srcFd) 47{ 48 Uri uri(infos->srcUri); 49 if (uri.GetAuthority() == "media") { 50 sptr<FileIoToken> remote = new (std::nothrow) IRemoteStub<FileIoToken>(); 51 if (!remote) { 52 LOGE("Failed to get remote object"); 53 return ENOMEM; 54 } 55 auto dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI); 56 if (!dataShareHelper) { 57 LOGE("Failed to connect to datashare"); 58 return E_PERMISSION; 59 } 60 srcFd = dataShareHelper->OpenFile(uri, CommonFunc::GetModeFromFlags(O_RDONLY)); 61 if (srcFd < 0) { 62 LOGE("Open media uri by data share fail. ret = %{public}d", srcFd); 63 return EPERM; 64 } 65 } else { 66 srcFd = open(srcPth.c_str(), O_RDONLY); 67 if (srcFd < 0) { 68 LOGE("Error opening src file descriptor. errno = %{public}d", errno); 69 return errno; 70 } 71 } 72 return ERRNO_NOERR; 73} 74 75static int SendFileCore(std::unique_ptr<DistributedFS::FDGuard> srcFdg, 76 std::unique_ptr<DistributedFS::FDGuard> destFdg, 77 std::shared_ptr<FileInfos> infos) 78{ 79 std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> sendFileReq = { 80 new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 81 if (sendFileReq == nullptr) { 82 LOGE("Failed to request heap memory."); 83 return ENOMEM; 84 } 85 int64_t offset = 0; 86 struct stat srcStat{}; 87 if (fstat(srcFdg->GetFD(), &srcStat) < 0) { 88 LOGE("Failed to get stat of file by fd: %{public}d ,errno = %{public}d", srcFdg->GetFD(), errno); 89 return errno; 90 } 91 int32_t ret = 0; 92 int64_t size = static_cast<int64_t>(srcStat.st_size); 93 while (size >= 0) { 94 ret = uv_fs_sendfile(nullptr, sendFileReq.get(), destFdg->GetFD(), srcFdg->GetFD(), 95 offset, MAX_SIZE, nullptr); 96 if (ret < 0) { 97 LOGE("Failed to sendfile by errno : %{public}d", errno); 98 return errno; 99 } 100 if (infos != nullptr && infos->taskSignal != nullptr) { 101 if (infos->taskSignal->CheckCancelIfNeed(infos->srcPath)) { 102 return ECANCELED; 103 } 104 } 105 offset += static_cast<int64_t>(ret); 106 size -= static_cast<int64_t>(ret); 107 if (ret == 0) { 108 break; 109 } 110 } 111 if (size != 0) { 112 LOGE("The execution of the sendfile task was terminated, remaining file size %{public}" PRIu64, size); 113 return EIO; 114 } 115 return ERRNO_NOERR; 116} 117 118static int FilterFunc(const struct dirent *filename) 119{ 120 if (std::string_view(filename->d_name) == "." || std::string_view(filename->d_name) == "..") { 121 return DISMATCH; 122 } 123 return MATCH; 124} 125 126struct NameList { 127 struct dirent **namelist = { nullptr }; 128 int direntNum = 0; 129}; 130 131static void Deleter(struct NameList *arg) 132{ 133 for (int i = 0; i < arg->direntNum; i++) { 134 free((arg->namelist)[i]); 135 (arg->namelist)[i] = nullptr; 136 } 137 free(arg->namelist); 138} 139 140std::string CopyImpl::GetRealPath(const std::string& path) 141{ 142 fs::path tempPath(path); 143 fs::path realPath{}; 144 for (const auto& component : tempPath) { 145 if (component == ".") { 146 continue; 147 } else if (component == "..") { 148 realPath = realPath.parent_path(); 149 } else { 150 realPath /= component; 151 } 152 } 153 return realPath.string(); 154} 155 156bool CopyImpl::IsFile(const std::string &path) 157{ 158 struct stat buf {}; 159 int ret = stat(path.c_str(), &buf); 160 if (ret == -1) { 161 LOGI("stat failed, errno is %{public}d, ", errno); 162 return false; 163 } 164 return (buf.st_mode & S_IFMT) == S_IFREG; 165} 166 167std::tuple<int, uint64_t> CopyImpl::GetFileSize(const std::string &path) 168{ 169 struct stat buf {}; 170 int ret = stat(path.c_str(), &buf); 171 if (ret == -1) { 172 LOGI("Stat failed."); 173 return { errno, 0 }; 174 } 175 return { ERRNO_NOERR, buf.st_size }; 176} 177 178bool CopyImpl::CheckFileValid(const std::string &filePath, std::shared_ptr<FileInfos> infos) 179{ 180 return infos->filePaths.count(filePath) != 0; 181} 182 183int CopyImpl::UpdateProgressSize(const std::string &filePath, 184 std::shared_ptr<ReceiveInfo> receivedInfo, std::shared_ptr<CjCallbackObject> callback) 185{ 186 auto [err, fileSize] = GetFileSize(filePath); 187 if (err != ERRNO_NOERR) { 188 LOGE("GetFileSize failed, err: %{public}d.", err); 189 return err; 190 } 191 auto size = fileSize; 192 auto iter = receivedInfo->fileList.find(filePath); 193 if (iter == receivedInfo->fileList.end()) { 194 receivedInfo->fileList.insert({ filePath, size }); 195 callback->progressSize += size; 196 } else { // file 197 if (size > iter->second) { 198 callback->progressSize += (size - iter->second); 199 iter->second = size; 200 } 201 } 202 return ERRNO_NOERR; 203} 204 205void CopyImpl::CheckOrCreatePath(const std::string &destPath) 206{ 207 if (!std::filesystem::exists(destPath)) { 208 LOGI("destPath not exist, destPath = %{public}s", destPath.c_str()); 209 auto file = open(destPath.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 210 if (file < 0) { 211 LOGE("Error opening file descriptor. errno = %{public}d", errno); 212 } 213 close(file); 214 } 215} 216 217int CopyImpl::MakeDir(const std::string &path) 218{ 219 std::filesystem::path destDir(path); 220 std::error_code errCode; 221 if (!std::filesystem::create_directory(destDir, errCode)) { 222 LOGE("Failed to create directory, error code: %{public}d", errCode.value()); 223 return errCode.value(); 224 } 225 return ERRNO_NOERR; 226} 227 228int CopyImpl::CopySubDir(const std::string &srcPath, const std::string &destPath, std::shared_ptr<FileInfos> infos) 229{ 230 if (!std::filesystem::exists(destPath)) { 231 int res = MakeDir(destPath); 232 if (res != ERRNO_NOERR) { 233 LOGE("Failed to mkdir"); 234 return res; 235 } 236 } 237 uint32_t watchEvents = IN_MODIFY; 238 if (infos->notifyFd >= 0) { 239 int newWd = inotify_add_watch(infos->notifyFd, destPath.c_str(), watchEvents); 240 if (newWd < 0) { 241 LOGE("inotify_add_watch, newWd is unvaild, newWd = %{public}d", newWd); 242 return errno; 243 } 244 { 245 std::lock_guard<std::recursive_mutex> lock(CopyImpl::mutex_); 246 auto iter = CopyImpl::cjCbMap_.find(*infos); 247 auto receiveInfo = FileManagement::CreateSharedPtr<ReceiveInfo>(); 248 if (receiveInfo == nullptr) { 249 LOGE("Failed to request heap memory."); 250 return ENOMEM; 251 } 252 receiveInfo->path = destPath; 253 if (iter == CopyImpl::cjCbMap_.end() || iter->second == nullptr) { 254 LOGE("Failed to find infos, srcPath = %{public}s, destPath = %{public}s", infos->srcPath.c_str(), 255 infos->destPath.c_str()); 256 return UNKNOWN_ERR; 257 } 258 iter->second->wds.push_back({ newWd, receiveInfo }); 259 } 260 } 261 return RecurCopyDir(srcPath, destPath, infos); 262} 263 264int CopyImpl::RecurCopyDir(const std::string &srcPath, const std::string &destPath, std::shared_ptr<FileInfos> infos) 265{ 266 std::unique_ptr<struct NameList, decltype(Deleter) *> pNameList = { new (std::nothrow) struct NameList, Deleter }; 267 if (pNameList == nullptr) { 268 LOGE("Failed to request heap memory."); 269 return ENOMEM; 270 } 271 int num = scandir(srcPath.c_str(), &(pNameList->namelist), FilterFunc, alphasort); 272 pNameList->direntNum = num; 273 274 for (int i = 0; i < num; i++) { 275 std::string src = srcPath + '/' + std::string((pNameList->namelist[i])->d_name); 276 std::string dest = destPath + '/' + std::string((pNameList->namelist[i])->d_name); 277 if ((pNameList->namelist[i])->d_type == DT_LNK) { 278 continue; 279 } 280 int ret = ERRNO_NOERR; 281 if ((pNameList->namelist[i])->d_type == DT_DIR) { 282 ret = CopySubDir(src, dest, infos); 283 } else { 284 infos->filePaths.insert(dest); 285 ret = CopyFile(src, dest, infos); 286 } 287 if (ret != ERRNO_NOERR) { 288 return ret; 289 } 290 } 291 return ERRNO_NOERR; 292} 293 294bool CopyImpl::IsDirectory(const std::string &path) 295{ 296 struct stat buf {}; 297 int ret = stat(path.c_str(), &buf); 298 if (ret == -1) { 299 LOGE("stat failed, errno is %{public}d, path is %{public}s", errno, path.c_str()); 300 return false; 301 } 302 return (buf.st_mode & S_IFMT) == S_IFDIR; 303} 304 305int CopyImpl::CopyDirFunc(const std::string &src, const std::string &dest, std::shared_ptr<FileInfos> infos) 306{ 307 LOGI("CopyDirFunc in, src = %{public}s, dest = %{public}s", src.c_str(), dest.c_str()); 308 size_t found = dest.find(src); 309 if (found != std::string::npos && found == 0) { 310 return EINVAL; 311 } 312 fs::path srcPath = fs::u8path(src); 313 std::string dirName; 314 if (srcPath.has_parent_path()) { 315 dirName = srcPath.parent_path().filename(); 316 } 317 std::string destStr = dest + "/" + dirName; 318 return CopySubDir(src, destStr, infos); 319} 320 321uint64_t CopyImpl::GetDirSize(std::shared_ptr<FileInfos> infos, std::string path) 322{ 323 std::unique_ptr<struct NameList, decltype(Deleter) *> pNameList = { new (std::nothrow) struct NameList, Deleter }; 324 if (pNameList == nullptr) { 325 LOGE("Failed to request heap memory."); 326 return ENOMEM; 327 } 328 int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort); 329 pNameList->direntNum = num; 330 331 long int size = 0; 332 for (int i = 0; i < num; i++) { 333 std::string dest = path + '/' + std::string((pNameList->namelist[i])->d_name); 334 if ((pNameList->namelist[i])->d_type == DT_LNK) { 335 continue; 336 } 337 if ((pNameList->namelist[i])->d_type == DT_DIR) { 338 size += static_cast<int64_t>(GetDirSize(infos, dest)); 339 } else { 340 struct stat st {}; 341 if (stat(dest.c_str(), &st) == -1) { 342 return size; 343 } 344 size += st.st_size; 345 } 346 } 347 return size; 348} 349 350std::shared_ptr<FileInfos> CopyImpl::InitCjFileInfo( 351 const std::string& srcUri, const std::string& destUri, sptr<CopyInfo> info) 352{ 353 auto infos = FileManagement::CreateSharedPtr<FileInfos>(); 354 if (infos == nullptr) { 355 LOGE("Failed to request heap memory by create FileInfos struct."); 356 return nullptr; 357 } 358 infos->srcUri = srcUri; 359 infos->destUri = destUri; 360 infos->listenerId = info->listenerId; 361 infos->copySignalId = info->signalId; 362 AppFileService::ModuleFileUri::FileUri srcFileUri(srcUri); 363 AppFileService::ModuleFileUri::FileUri destFileUri(destUri); 364 infos->srcPath = srcFileUri.GetRealPath(); 365 infos->destPath = destFileUri.GetPath(); 366 infos->srcPath = GetRealPath(infos->srcPath); 367 infos->destPath = GetRealPath(infos->destPath); 368 infos->notifyTime = std::chrono::steady_clock::now() + NOTIFY_PROGRESS_DELAY; 369 if (info->listenerId > 0) { 370 infos->hasListener = true; 371 } 372 auto signal = FFI::FFIData::GetData<TaskSignalImpl>(infos->copySignalId); 373 if (signal != nullptr && signal->signalEntity != nullptr) { 374 infos->taskSignal = signal->signalEntity->taskSignal_; 375 } 376 return infos; 377} 378 379void CopyImpl::ReceiveComplete(CProgress data, 380 std::shared_ptr<FileInfos> infos, std::shared_ptr<CjCallbackObject> callback) 381{ 382 if (callback == nullptr) { 383 LOGE("callback pointer is nullptr."); 384 return; 385 } 386 auto processedSize = data.processedSize; 387 if (processedSize < callback->maxProgressSize) { 388 return; 389 } 390 callback->maxProgressSize = processedSize; 391 392 if (callback->callback == nullptr) { 393 LOGI("Empty callback."); 394 return; 395 } 396 callback->callback(data); 397} 398 399void CopyImpl::OnFileReceive(std::shared_ptr<FileInfos> infos) 400{ 401 auto callback = GetRegisteredListener(infos); 402 if (callback == nullptr) { 403 LOGE("failed to get listener progress"); 404 return; 405 } 406 CProgress data = {.processedSize = callback->progressSize, 407 .totalSize = callback->totalSize}; 408 ReceiveComplete(data, infos, callback); 409} 410 411std::shared_ptr<ReceiveInfo> CopyImpl::GetReceivedInfo(int wd, std::shared_ptr<CjCallbackObject> callback) 412{ 413 auto it = find_if(callback->wds.begin(), callback->wds.end(), [wd](const auto& item) { 414 return item.first == wd; 415 }); 416 if (it != callback->wds.end()) { 417 return it->second; 418 } 419 return nullptr; 420} 421 422int CopyImpl::CopyFile(const std::string &src, const std::string &dest, std::shared_ptr<FileInfos> infos) 423{ 424 LOGI("src = %{public}s, dest = %{public}s", src.c_str(), dest.c_str()); 425 int32_t srcFd = -1; 426 int32_t ret = OpenSrcFile(src, infos, srcFd); 427 if (srcFd < 0) { 428 return ret; 429 } 430 auto destFd = open(dest.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); 431 if (destFd < 0) { 432 LOGE("Error opening dest file descriptor. errno = %{public}d", errno); 433 close(srcFd); 434 return errno; 435 } 436 auto srcFdg = FileManagement::CreateUniquePtr<DistributedFS::FDGuard>(srcFd, true); 437 auto destFdg = FileManagement::CreateUniquePtr<DistributedFS::FDGuard>(destFd, true); 438 if (srcFdg == nullptr || destFdg == nullptr) { 439 LOGE("Failed to request heap memory."); 440 close(srcFd); 441 close(destFd); 442 return ENOMEM; 443 } 444 return SendFileCore(move(srcFdg), move(destFdg), infos); 445} 446 447std::shared_ptr<CjCallbackObject> CopyImpl::GetRegisteredListener(std::shared_ptr<FileInfos> infos) 448{ 449 std::lock_guard<std::recursive_mutex> lock(mutex_); 450 auto iter = cjCbMap_.find(*infos); 451 if (iter == cjCbMap_.end()) { 452 LOGE("It is not registered."); 453 return nullptr; 454 } 455 return iter->second; 456} 457 458std::tuple<bool, int, bool> CopyImpl::HandleProgress( 459 inotify_event *event, std::shared_ptr<FileInfos> infos, std::shared_ptr<CjCallbackObject> callback) 460{ 461 if (callback == nullptr) { 462 return { true, EINVAL, false }; 463 } 464 auto receivedInfo = GetReceivedInfo(event->wd, callback); 465 if (receivedInfo == nullptr) { 466 return { true, EINVAL, false }; 467 } 468 std::string fileName = receivedInfo->path; 469 if (event->len > 0) { // files under subdir 470 fileName += "/" + std::string(event->name); 471 if (!CheckFileValid(fileName, infos)) { 472 return { true, EINVAL, false }; 473 } 474 auto err = UpdateProgressSize(fileName, receivedInfo, callback); 475 if (err != ERRNO_NOERR) { 476 return { false, err, false }; 477 } 478 } else { 479 auto [err, fileSize] = GetFileSize(fileName); 480 if (err != ERRNO_NOERR) { 481 return { false, err, false }; 482 } 483 callback->progressSize = fileSize; 484 } 485 return { true, callback->errorCode, true }; 486} 487 488void CopyImpl::ReadNotifyEvent(std::shared_ptr<FileInfos> infos) 489{ 490 char buf[BUF_SIZE] = { 0 }; 491 struct inotify_event *event = nullptr; 492 int len = 0; 493 int64_t index = 0; 494 auto callback = GetRegisteredListener(infos); 495 while (((len = read(infos->notifyFd, &buf, sizeof(buf))) < 0) && (errno == EINTR)) {} 496 while (infos->run && index < len) { 497 event = reinterpret_cast<inotify_event *>(buf + index); 498 auto [needContinue, errCode, needSend] = HandleProgress(event, infos, callback); 499 if (!needContinue) { 500 infos->exceptionCode = errCode; 501 return; 502 } 503 if (needContinue && !needSend) { 504 index += static_cast<int64_t>(sizeof(struct inotify_event) + event->len); 505 continue; 506 } 507 if (callback->progressSize == callback->totalSize) { 508 infos->run = false; 509 return; 510 } 511 auto currentTime = std::chrono::steady_clock::now(); 512 if (currentTime >= infos->notifyTime) { 513 OnFileReceive(infos); 514 infos->notifyTime = currentTime + NOTIFY_PROGRESS_DELAY; 515 } 516 index += static_cast<int64_t>(sizeof(struct inotify_event) + event->len); 517 } 518} 519 520void CopyImpl::GetNotifyEvent(std::shared_ptr<FileInfos> infos) 521{ 522 auto callback = GetRegisteredListener(infos); 523 if (callback == nullptr) { 524 infos->exceptionCode = EINVAL; 525 return; 526 } 527 prctl(PR_SET_NAME, "NotifyThread"); 528 nfds_t nfds = 2; 529 struct pollfd fds[2]; 530 fds[0].events = 0; 531 fds[1].events = POLLIN; 532 fds[0].fd = infos->eventFd; 533 fds[1].fd = infos->notifyFd; 534 while (infos->run && infos->exceptionCode == ERRNO_NOERR && infos->eventFd != -1 && infos->notifyFd != -1) { 535 auto ret = poll(fds, nfds, -1); 536 if (ret > 0) { 537 if (static_cast<unsigned short>(fds[0].revents) & POLLNVAL) { 538 infos->run = false; 539 return; 540 } 541 if (static_cast<unsigned short>(fds[1].revents) & POLLIN) { 542 ReadNotifyEvent(infos); 543 } 544 } else if (ret < 0 && errno == EINTR) { 545 continue; 546 } else { 547 infos->exceptionCode = errno; 548 return; 549 } 550 } 551} 552 553void CopyImpl::StartNotify(std::shared_ptr<FileInfos> infos, std::shared_ptr<CjCallbackObject> callback) 554{ 555 if (infos->hasListener && callback != nullptr) { 556 callback->notifyHandler = std::thread([infos] { 557 GetNotifyEvent(infos); 558 }); 559 } 560} 561 562int CopyImpl::ExecCopy(std::shared_ptr<FileInfos> infos) 563{ 564 if (IsFile(infos->srcPath) && IsFile(infos->destPath)) { 565 // copyFile 566 return CopyFile(infos->srcPath.c_str(), infos->destPath.c_str(), infos); 567 } 568 if (IsDirectory(infos->srcPath) && IsDirectory(infos->destPath)) { 569 if (infos->srcPath.back() != '/') { 570 infos->srcPath += '/'; 571 } 572 if (infos->destPath.back() != '/') { 573 infos->destPath += '/'; 574 } 575 // copyDir 576 return CopyDirFunc(infos->srcPath.c_str(), infos->destPath.c_str(), infos); 577 } 578 return EINVAL; 579} 580 581std::shared_ptr<CjCallbackObject> CopyImpl::RegisterListener(std::shared_ptr<FileInfos>& infos) 582{ 583 auto callback = FileManagement::CreateSharedPtr<CjCallbackObject>(infos->listenerId); 584 if (callback == nullptr) { 585 LOGE("Failed to request heap memory by create callback object."); 586 return nullptr; 587 } 588 std::lock_guard<std::recursive_mutex> lock(mutex_); 589 auto iter = cjCbMap_.find(*infos); 590 if (iter != cjCbMap_.end()) { 591 LOGE("Regist copy listener, already registered.") 592 return nullptr; 593 } 594 cjCbMap_.insert({*infos, callback}); 595 return callback; 596} 597 598void CopyImpl::UnregisterListener(std::shared_ptr<FileInfos> infos) 599{ 600 if (infos == nullptr) { 601 LOGE("infos is nullptr"); 602 return; 603 } 604 std::lock_guard<std::recursive_mutex> lock(mutex_); 605 auto iter = cjCbMap_.find(*infos); 606 if (iter == cjCbMap_.end()) { 607 LOGI("It is not be registered."); 608 return; 609 } 610 cjCbMap_.erase(*infos); 611} 612 613bool CopyImpl::IsRemoteUri(const std::string& uri) 614{ 615 return uri.find(NETWORK_PARA) != uri.npos; 616} 617 618int64_t CopyImpl::DoCopy(std::shared_ptr<FileInfos> infos, std::shared_ptr<CjCallbackObject> callback) 619{ 620 if (IsRemoteUri(infos->srcUri)) { 621 if (infos->taskSignal != nullptr) { 622 infos->taskSignal->MarkRemoteTask(); 623 } 624 auto ret = TransListener::CopyFileFromSoftBus( 625 infos->srcUri, infos->destUri, infos, std::move(callback)); 626 return ret; 627 } 628 auto result = ExecLocal(infos, callback); 629 CloseNotifyFd(infos, callback); 630 infos->run = false; 631 WaitNotifyFinished(callback); 632 if (result != ERRNO_NOERR) { 633 infos->exceptionCode = result; 634 return infos->exceptionCode; 635 } 636 CopyComplete(infos, callback); 637 return infos->exceptionCode; 638} 639 640int64_t CopyImpl::ExecLocal(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback) 641{ 642 if (IsFile(infos->srcPath)) { 643 if (infos->srcPath == infos->destPath) { 644 LOGE("The src and dest is same, path = %{public}s", infos->srcPath.c_str()); 645 return EINVAL; 646 } 647 CheckOrCreatePath(infos->destPath); 648 } 649 if (!infos->hasListener) { 650 return ExecCopy(infos); 651 } 652 auto ret = SubscribeLocalListener(infos, callback); 653 if (ret != ERRNO_NOERR) { 654 LOGE("Failed to subscribe local listener, errno = %{public}" PRIu64, ret); 655 return ret; 656 } 657 StartNotify(infos, callback); 658 return ExecCopy(infos); 659} 660 661int64_t CopyImpl::SubscribeLocalListener(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback) 662{ 663 infos->notifyFd = inotify_init(); 664 if (infos->notifyFd < 0) { 665 LOGE("Failed to init inotify, errno:%{public}d", errno); 666 return errno; 667 } 668 infos->eventFd = eventfd(0, EFD_CLOEXEC); 669 if (infos->eventFd < 0) { 670 LOGE("Failed to init eventFd, errno:%{public}d", errno); 671 return errno; 672 } 673 callback->notifyFd = infos->notifyFd; 674 callback->eventFd = infos->eventFd; 675 int newWd = inotify_add_watch(infos->notifyFd, infos->destPath.c_str(), IN_MODIFY); 676 if (newWd < 0) { 677 LOGE("Failed to add watch, errno = %{public}d, notifyFd: %{public}d, destPath: %{public}s", 678 errno, infos->notifyFd, infos->destPath.c_str()); 679 CloseNotifyFd(infos, callback); 680 return errno; 681 } 682 auto receiveInfo = FileManagement::CreateSharedPtr<ReceiveInfo>(); 683 if (receiveInfo == nullptr) { 684 LOGE("Failed to request heap memory."); 685 inotify_rm_watch(infos->notifyFd, newWd); 686 CloseNotifyFd(infos, callback); 687 return ENOMEM; 688 } 689 receiveInfo->path = infos->destPath; 690 callback->wds.push_back({ newWd, receiveInfo }); 691 if (IsDirectory(infos->srcPath)) { 692 callback->totalSize = GetDirSize(infos, infos->srcPath); 693 return ERRNO_NOERR; 694 } 695 auto [err, fileSize] = GetFileSize(infos->srcPath); 696 if (err == ERRNO_NOERR) { 697 callback->totalSize = fileSize; 698 } 699 return err; 700} 701 702void CopyImpl::CloseNotifyFd(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback) 703{ 704 callback->CloseFd(); 705 infos->eventFd = -1; 706 infos->notifyFd = -1; 707} 708 709void CopyImpl::WaitNotifyFinished(std::shared_ptr<CjCallbackObject>& callback) 710{ 711 if (callback != nullptr) { 712 if (callback->notifyHandler.joinable()) { 713 callback->notifyHandler.join(); 714 } 715 } 716} 717 718void CopyImpl::CopyComplete(std::shared_ptr<FileInfos>& infos, std::shared_ptr<CjCallbackObject>& callback) 719{ 720 if (callback != nullptr && infos->hasListener) { 721 callback->progressSize = callback->totalSize; 722 OnFileReceive(infos); 723 } 724} 725 726void CopyImpl::Copy(const char* srcUri, const char* destUri, sptr<CopyInfo> info) 727{ 728 if (srcUri == nullptr || destUri == nullptr) { 729 LOGE("Invalid input."); 730 return; 731 } 732 std::string src(srcUri); 733 std::string dest(destUri); 734 std::shared_ptr<FileInfos> infos = InitCjFileInfo(src, dest, info); 735 if (infos == nullptr) { 736 return; 737 } 738 auto callback = RegisterListener(infos); 739 if (callback == nullptr) { 740 return; 741 } 742 DoCopy(infos, callback); 743 UnregisterListener(infos); 744} 745 746CopyInfo::~CopyInfo() {} 747} 748}