From 2a4735dbbc414d078b151870d04823afb619cc15 Mon Sep 17 00:00:00 2001 From: Hollokin Date: Tue, 5 Dec 2023 21:48:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E6=8B=B7=E8=B4=9D=E9=97=AE?= =?UTF-8?q?=E9=A2=98=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Hollokin --- .../kits/js/src/mod_fs/properties/copy.cpp | 238 ++++++++---------- .../kits/js/src/mod_fs/properties/copy.h | 33 ++- 2 files changed, 121 insertions(+), 150 deletions(-) diff --git a/interfaces/kits/js/src/mod_fs/properties/copy.cpp b/interfaces/kits/js/src/mod_fs/properties/copy.cpp index 77489b052..e86665ee8 100644 --- a/interfaces/kits/js/src/mod_fs/properties/copy.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/copy.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -73,7 +74,6 @@ tuple Copy::GetListenerFromOptionArg(napi_env env, const NFuncArg &f { if (funcArg.GetArgc() >= NARG_CNT::THREE) { NVal op(env, funcArg[NARG_POS::THIRD]); - if (op.HasProp("progressListener") && !op.GetProp("progressListener").TypeIs(napi_undefined)) { if (!op.GetProp("progressListener").TypeIs(napi_function)) { HILOGE("Illegal options.progressListener type"); @@ -93,8 +93,7 @@ bool Copy::IsRemoteUri(const std::string &uri) bool Copy::IsDirectory(const std::string &path) { - struct stat buf { - }; + struct stat buf {}; int ret = stat(path.c_str(), &buf); if (ret == -1) { HILOGE("stat failed, errno is %{public}d, path is %{public}s", errno, path.c_str()); @@ -105,8 +104,7 @@ bool Copy::IsDirectory(const std::string &path) bool Copy::IsFile(const std::string &path) { - struct stat buf { - }; + struct stat buf {}; int ret = stat(path.c_str(), &buf); if (ret == -1) { HILOGI("stat failed, errno is %{public}d, ", errno); @@ -117,8 +115,7 @@ bool Copy::IsFile(const std::string &path) tuple Copy::GetFileSize(const std::string &path) { - struct stat buf { - }; + struct stat buf {}; int ret = stat(path.c_str(), &buf); if (ret == -1) { HILOGI("Stat failed."); @@ -127,23 +124,14 @@ tuple Copy::GetFileSize(const std::string &path) return { ERRNO_NOERR, buf.st_size }; } -bool Copy::CheckValidParam(const std::string &srcUri, const std::string &destUri) +void Copy::CheckOrCreatePath(const std::string &destPath) { - auto srcPath = ConvertUriToPath(srcUri); - auto destPath = ConvertUriToPath(destUri); if (!filesystem::exists(destPath)) { HILOGE("destPath not exist, destPath = %{public}s", destPath.c_str()); ofstream out; out.open(destPath.c_str()); out.close(); } - if (IsDirectory(srcPath)) { - return IsDirectory(destPath); - } - if (IsFile(srcPath)) { - return IsFile(destPath); - } - return false; } int Copy::CopyFile(const string &src, const string &dest) @@ -236,6 +224,9 @@ uint64_t Copy::GetDirSize(std::shared_ptr infos, std::string path) long int size = 0; for (int i = 0; i < num; i++) { string dest = path + '/' + string((pNameList->namelist[i])->d_name); + if ((pNameList->namelist[i])->d_type == DT_LNK) { + continue; + } if ((pNameList->namelist[i])->d_type == DT_DIR) { return size += GetDirSize(infos, dest); } @@ -261,6 +252,9 @@ int Copy::RecurCopyDir(const string &srcPath, const string &destPath, std::share for (int i = 0; i < num; i++) { string src = srcPath + '/' + string((pNameList->namelist[i])->d_name); string dest = destPath + '/' + string((pNameList->namelist[i])->d_name); + if ((pNameList->namelist[i])->d_type == DT_LNK) { + continue; + } if ((pNameList->namelist[i])->d_type == DT_DIR) { return CopySubDir(src, dest, infos); } @@ -285,47 +279,60 @@ int Copy::CopyDirFunc(const string &src, const string &dest, std::shared_ptr infos, - std::shared_ptr callback) +int Copy::ExecLocal(std::shared_ptr infos, std::shared_ptr callback) { - if (!infos->listener.TypeIs(napi_function)) { - return ERRNO_NOERR; + CheckOrCreatePath(infos->destPath); + if (!infos->hasListener) { + return ExecCopy(infos); + } + auto ret = SubscribeLocalListener(infos, callback); + if (ret != ERRNO_NOERR) { + HILOGE("Failed to subscribe local listener, errno = %{public}d", ret); + return ret; } + StartNotify(infos, callback); + return ExecCopy(infos); +} + +int Copy::SubscribeLocalListener(std::shared_ptr infos, + std::shared_ptr callback) +{ infos->notifyFd = inotify_init(); if (infos->notifyFd < 0) { HILOGE("Failed to init inotify, errno:%{public}d", errno); return errno; } - uint32_t watchEvents = IN_MODIFY; - int newWd = inotify_add_watch(infos->notifyFd, infos->destPath.c_str(), watchEvents); + callback->notifyFd = infos->notifyFd; + int newWd = inotify_add_watch(infos->notifyFd, infos->destPath.c_str(), IN_MODIFY); if (newWd < 0) { - auto errNo = errno; - HILOGE("Failed to add inotify watch, errno:%{public}d, notifyFd = %{public}d, destPath = %{public}s", errNo, - infos->notifyFd, infos->destPath.c_str()); + auto errCode = errno; + HILOGE("Failed to add watch, errno = %{public}d, notifyFd: %{public}d, destPath: %{public}s", errno, + infos->notifyFd, infos->destPath.c_str()); close(infos->notifyFd); - return errNo; + infos->notifyFd = -1; + callback->notifyFd = -1; + return errCode; } auto receiveInfo = CreateSharedPtr(); if (receiveInfo == nullptr) { HILOGE("Failed to request heap memory."); + inotify_rm_watch(infos->notifyFd, newWd); + close(infos->notifyFd); + infos->notifyFd = -1; + callback->notifyFd = -1; return ENOMEM; } receiveInfo->path = infos->destPath; callback->wds.push_back({ newWd, receiveInfo }); - if (IsFile(infos->srcPath)) { - auto [err, fileSize] = GetFileSize(infos->srcPath); - if (err != ERRNO_NOERR) { - return err; - } - callback->totalSize = fileSize; - } else { + if (IsDirectory(infos->srcPath)) { callback->totalSize = GetDirSize(infos, infos->srcPath); + return ERRNO_NOERR; } - inotify_rm_watch(infos->notifyFd, newWd); - close(infos->notifyFd); - HILOGE("Can not copy repeat."); - return EINVAL; + auto [err, fileSize] = GetFileSize(infos->srcPath); + if (err == ERRNO_NOERR) { + callback->totalSize = fileSize; + } + return err; } std::shared_ptr Copy::RegisterListener(napi_env env, const std::shared_ptr &infos) @@ -338,7 +345,7 @@ std::shared_ptr Copy::RegisterListener(napi_env env, const std std::lock_guard lock(mutex_); auto iter = jsCbMap_.find(*infos); if (iter != jsCbMap_.end()) { - HILOGI("Copy::RegisterListener, already registered."); + HILOGE("Copy::RegisterListener, already registered."); return nullptr; } jsCbMap_.insert({ *infos, callback }); @@ -358,7 +365,6 @@ void Copy::UnregisterListener(std::shared_ptr infos) return; } jsCbMap_.erase(*infos); - HILOGD("UnregisterListener end."); } void Copy::ReceiveComplete(uv_work_t *work, int stat) @@ -390,7 +396,7 @@ void Copy::ReceiveComplete(uv_work_t *work, int stat) return; } NVal obj = NVal::CreateObject(env); - if (processedSize <= numeric_limits::max() && entry->totalSize <= numeric_limits::max()) { + if (processedSize <= numeric_limits::max() && entry->totalSize <= numeric_limits::max()) { obj.AddProp("processedSize", NVal::CreateInt64(env, processedSize).val_); obj.AddProp("totalSize", NVal::CreateInt64(env, entry->totalSize).val_); } @@ -400,34 +406,12 @@ void Copy::ReceiveComplete(uv_work_t *work, int stat) if (status != napi_ok) { HILOGE("Failed to get result, status: %{public}d.", status); } - if (entry->progressSize == entry->totalSize) { - HILOGI("entry->progressSize == entry->totalSize, %" PRId64, entry->progressSize); - UnregisterListener(entry->fileInfos); - } status = napi_close_handle_scope(env, scope); if (status != napi_ok) { HILOGE("Failed to close scope, status: %{public}d.", status); } } -void Copy::UnregisterListenerComplete(uv_work_t *work, int stat) -{ - if (work == nullptr) { - HILOGE("uv_work_t pointer is nullptr."); - return; - } - - std::shared_ptr entry(static_cast(work->data), [work](UvEntry *data) { - delete data; - delete work; - }); - if (entry == nullptr) { - HILOGE("entry pointer is nullptr."); - return; - } - UnregisterListener(entry->fileInfos); -} - uv_work_t *Copy::GetUVwork(std::shared_ptr infos) { UvEntry *entry = nullptr; @@ -451,6 +435,7 @@ uv_work_t *Copy::GetUVwork(std::shared_ptr infos) uv_work_t *work = new (std::nothrow) uv_work_t; if (work == nullptr) { HILOGE("Failed to create uv_work_t pointer"); + delete entry; return nullptr; } work->data = entry; @@ -470,19 +455,6 @@ void Copy::OnFileReceive(std::shared_ptr infos) loop, work, [](uv_work_t *work) {}, reinterpret_cast(ReceiveComplete)); } -void Copy::OnUnregisterListener(std::shared_ptr infos) -{ - uv_work_t *work = GetUVwork(infos); - if (work == nullptr) { - HILOGE("Failed to create uv_work_t pointer"); - return; - } - uv_loop_s *loop = nullptr; - napi_get_uv_event_loop(infos->env, &loop); - uv_queue_work( - loop, work, [](uv_work_t *work) {}, reinterpret_cast(UnregisterListenerComplete)); -} - fd_set Copy::InitFds(int notifyFd) { fd_set fds; @@ -493,12 +465,9 @@ fd_set Copy::InitFds(int notifyFd) std::shared_ptr Copy::GetReceivedInfo(int wd, std::shared_ptr callback) { - std::string path; - auto wds = callback->wds; - auto it = wds.begin(); - for (; it != wds.end(); ++it) { - if (it->first == wd) { - return it->second; + for (auto &it : callback->wds) { + if (it.first == wd) { + return it.second; } } return nullptr; @@ -509,8 +478,9 @@ bool Copy::CheckFileValid(const std::string &filePath, std::shared_ptrfilePaths.count(filePath) != 0; } -int Copy::UpdateProgressSize(const std::string &filePath, std::shared_ptr infos, - std::shared_ptr receivedInfo, std::shared_ptr callback) +int Copy::UpdateProgressSize(const std::string &filePath, + std::shared_ptr receivedInfo, + std::shared_ptr callback) { auto [err, fileSize] = GetFileSize(filePath); if (err != ERRNO_NOERR) { @@ -555,7 +525,7 @@ tuple Copy::HandleProgress( if (!CheckFileValid(fileName, infos)) { return { true, EINVAL, false }; } - auto err = UpdateProgressSize(fileName, infos, receivedInfo, callback); + auto err = UpdateProgressSize(fileName, receivedInfo, callback); if (err != ERRNO_NOERR) { return { false, err, false }; } @@ -569,64 +539,43 @@ tuple Copy::HandleProgress( return { true, ERRNO_NOERR, true }; } -void Copy::RemoveWatch(int notifyFd, std::shared_ptr callback) -{ - for (auto item : callback->wds) { - inotify_rm_watch(notifyFd, item.first); - } - close(notifyFd); -} - void Copy::GetNotifyEvent(std::shared_ptr infos) { - if (infos->run || infos->notifyFd < 0) { - HILOGE("Already run or notifyFd is invalid, notifyFd: %{public}d.", infos->notifyFd); - infos->exceptionCode = EINVAL; - return; - } + prctl(PR_SET_NAME, "NotifyThread"); infos->run = true; char buf[BUF_SIZE] = { 0 }; struct inotify_event *event = nullptr; fd_set fds = InitFds(infos->notifyFd); while (infos->run && infos->exceptionCode == ERRNO_NOERR) { auto ret = select(infos->notifyFd + 1, &fds, nullptr, nullptr, nullptr); - if (ret <= 0) { + if (ret < 0) { HILOGD("Failed to select, ret = %{public}d.", ret); infos->exceptionCode = errno; break; } int len, index = 0; while (((len = read(infos->notifyFd, &buf, sizeof(buf))) < 0) && (errno == EINTR)) {}; - while (index < len) { + while (index < len && infos->run) { event = reinterpret_cast(buf + index); auto callback = GetRegisteredListener(infos); if (callback == nullptr) { infos->exceptionCode = EINVAL; - infos->run = false; return; } auto [needContinue, errCode, needSend] = HandleProgress(event, infos, callback); if (!needContinue) { infos->exceptionCode = errCode; - RemoveWatch(infos->notifyFd, callback); callback = nullptr; - OnUnregisterListener(infos); return; } if (needContinue && !needSend) { index += sizeof(struct inotify_event) + event->len; continue; } - if (callback->progressSize == callback->totalSize) { - infos->run = false; - RemoveWatch(infos->notifyFd, callback); - } - callback = nullptr; OnFileReceive(infos); index += sizeof(struct inotify_event) + event->len; } } - OnUnregisterListener(infos); } std::string Copy::ConvertUriToPath(const std::string &uri) @@ -648,15 +597,19 @@ tuple> Copy::CreateFileInfos( infos->listener = listener; infos->srcPath = ConvertUriToPath(infos->srcUri); infos->destPath = ConvertUriToPath(infos->destUri); + + if (listener) { + infos->hasListener = true; + } return { ERRNO_NOERR, infos }; } -void Copy::StartNotify(std::shared_ptr infos) +void Copy::StartNotify(std::shared_ptr infos, std::shared_ptr callback) { - if (infos->notifyFd != -1) { - std::thread([infos] { + if (infos->hasListener && callback != nullptr) { + callback->notifyHandler = std::thread([infos] { GetNotifyEvent(infos); - }).detach(); + }); } } @@ -675,6 +628,10 @@ int Copy::ExecCopy(std::shared_ptr infos) int Copy::ParseJsParam(napi_env env, NFuncArg &funcArg, std::shared_ptr &fileInfos) { + if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) { + HILOGE("Number of arguments unmatched"); + return E_PARAMS; + } auto [succSrc, srcUri] = ParseJsOperand(env, { env, funcArg[NARG_POS::FIRST] }); auto [succDest, destUri] = ParseJsOperand(env, { env, funcArg[NARG_POS::SECOND] }); auto [succOptions, listener] = GetListenerFromOptionArg(env, funcArg); @@ -682,11 +639,6 @@ int Copy::ParseJsParam(napi_env env, NFuncArg &funcArg, std::shared_ptr callback) +{ + if (callback != nullptr) { + if (callback->notifyHandler.joinable()) { + callback->notifyHandler.join(); + } + } +} + +void Copy::CopyComplete(std::shared_ptr infos, std::shared_ptr callback) +{ + if (callback != nullptr) { + callback->progressSize = callback->totalSize; + OnFileReceive(infos); + } +} + napi_value Copy::Async(napi_env env, napi_callback_info info) { NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) { - HILOGE("Number of arguments unmatched"); - NError(E_PARAMS).ThrowErr(env); - return nullptr; - } std::shared_ptr infos = nullptr; auto result = ParseJsParam(env, funcArg, infos); if (result != ERRNO_NOERR) { @@ -714,25 +678,19 @@ napi_value Copy::Async(napi_env env, napi_callback_info info) NError(E_UNKNOWN_ERROR).ThrowErr(env); return nullptr; } - if (!IsRemoteUri(infos->srcUri)) { - auto ret = SubscribeLocalListener(env, infos, callback); - if (ret != ERRNO_NOERR) { - NError(ret).ThrowErr(env); - return nullptr; - } - } - std::shared_ptr tempInfos = infos; - auto cbExec = [env, tempInfos, callback]() -> NError { - if (IsRemoteUri(tempInfos->srcUri)) { - // copyRemoteUri - return TransListener::CopyFileFromSoftBus(tempInfos->srcUri, tempInfos->destUri, std::move(callback)); + auto cbExec = [infos, callback]() -> NError { + if (IsRemoteUri(infos->srcUri)) { + return TransListener::CopyFileFromSoftBus(infos->srcUri, infos->destUri, std::move(callback)); } - StartNotify(tempInfos); - auto result = ExecCopy(tempInfos); + auto result = Copy::ExecLocal(infos, callback); + infos->run = false; + WaitNotifyFinished(callback); if (result != ERRNO_NOERR) { - tempInfos->exceptionCode = result; + infos->exceptionCode = result; + return NError(infos->exceptionCode); } - return NError(tempInfos->exceptionCode); + CopyComplete(infos, callback); + return NError(infos->exceptionCode); }; auto cbCompl = [infos](napi_env env, NError err) -> NVal { diff --git a/interfaces/kits/js/src/mod_fs/properties/copy.h b/interfaces/kits/js/src/mod_fs/properties/copy.h index a35d0ba33..03d67002b 100644 --- a/interfaces/kits/js/src/mod_fs/properties/copy.h +++ b/interfaces/kits/js/src/mod_fs/properties/copy.h @@ -38,12 +38,24 @@ struct ReceiveInfo { struct JsCallbackObject { napi_env env = nullptr; LibN::NRef nRef; + int32_t notifyFd = -1; std::vector>> wds; uint64_t totalSize = 0; uint64_t progressSize = 0; uint64_t maxProgressSize = 0; + std::thread notifyHandler; explicit JsCallbackObject(napi_env env, LibN::NVal jsVal) : env(env), nRef(jsVal) {} - ~JsCallbackObject() = default; + ~JsCallbackObject() + { + if (notifyFd == -1) { + return; + } + for (auto item : wds) { + inotify_rm_watch(notifyFd, item.first); + } + close(notifyFd); + notifyFd = -1; + } }; struct FileInfos { @@ -53,6 +65,7 @@ struct FileInfos { std::string destPath; int32_t notifyFd = -1; bool run = false; + bool hasListener = false; napi_env env; NVal listener; std::set filePaths; @@ -93,23 +106,22 @@ private: // operator of napi static tuple ParseJsOperand(napi_env env, NVal pathOrFdFromJsArg); static tuple GetListenerFromOptionArg(napi_env env, const NFuncArg &funcArg); - static bool CheckValidParam(const std::string &srcUri, const std::string &destUri); + static void CheckOrCreatePath(const std::string &path); static int ParseJsParam(napi_env env, NFuncArg &funcArg, std::shared_ptr &fileInfos); // operator of local listener + static int ExecLocal(std::shared_ptr infos, std::shared_ptr callback); + static void CopyComplete(std::shared_ptr infos, std::shared_ptr callback); + static void WaitNotifyFinished(std::shared_ptr callback); static fd_set InitFds(int notifyFd); - static int SubscribeLocalListener( - napi_env env, std::shared_ptr infos, std::shared_ptr callback); + static int SubscribeLocalListener(std::shared_ptr infos, std::shared_ptr callback); static std::shared_ptr RegisterListener(napi_env env, const std::shared_ptr &infos); static void OnFileReceive(std::shared_ptr infos); static void GetNotifyEvent(std::shared_ptr infos); - static void StartNotify(std::shared_ptr infos); + static void StartNotify(std::shared_ptr infos, std::shared_ptr callback); static uv_work_t *GetUVwork(std::shared_ptr infos); static void ReceiveComplete(uv_work_t *work, int stat); - static void OnUnregisterListener(std::shared_ptr infos); - static void UnregisterListenerComplete(uv_work_t *work, int stat); static std::shared_ptr GetRegisteredListener(std::shared_ptr infos); - static void RemoveWatch(int notifyFd, std::shared_ptr callback); // operator of file static int RecurCopyDir(const string &srcPath, const string &destPath, std::shared_ptr infos); @@ -124,8 +136,9 @@ private: static int ExecCopy(std::shared_ptr infos); // operator of file size - static int UpdateProgressSize(const std::string &filePath, std::shared_ptr infos, - std::shared_ptr receivedInfo, std::shared_ptr callback); + static int UpdateProgressSize(const std::string &filePath, + std::shared_ptr receivedInfo, + std::shared_ptr callback); static tuple HandleProgress( inotify_event *event, std::shared_ptr infos, std::shared_ptr callback); static std::shared_ptr GetReceivedInfo(int wd, std::shared_ptr callback); -- Gitee