From fafeb28757841a1a9836835abb167e84334a322d Mon Sep 17 00:00:00 2001 From: fengjq Date: Sun, 10 Dec 2023 20:36:32 +0800 Subject: [PATCH] Bugfix for Trash in recover files Signed-off-by: fengjq --- .../trash/src/file_trash_n_exporter.cpp | 283 +++++++----------- utils/file_util.h | 79 +++-- 2 files changed, 139 insertions(+), 223 deletions(-) diff --git a/interfaces/kits/native/trash/src/file_trash_n_exporter.cpp b/interfaces/kits/native/trash/src/file_trash_n_exporter.cpp index 4f808c8b..a0179a2e 100644 --- a/interfaces/kits/native/trash/src/file_trash_n_exporter.cpp +++ b/interfaces/kits/native/trash/src/file_trash_n_exporter.cpp @@ -36,6 +36,8 @@ using namespace FileManagement::LibN; using namespace FileManagement; using namespace std; +static int RenameDir(const string &dirPath, const string &sourceFilePath); + static bool CheckCallingPermission(const std::string &permission) { Security::AccessToken::AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID(); @@ -191,37 +193,6 @@ static string FindSourceFilePath(const string &path) return realFilePath; } -static bool Mkdirs(const string &path, bool isDir, string &newRecoveredPath) -{ - HILOG_INFO("Mkdirs: path = %{public}s", path.c_str()); - string recoveredPath = path; - string folderName = ""; - size_t lastPos = 0; - if (recoveredPath.length() == 0) { - return false; - } - // if argument uri is dir, then add "/" - if (isDir) { - recoveredPath = recoveredPath + "/"; - } - - for (size_t i = 1; i < recoveredPath.length(); ++i) { - if (recoveredPath[i] != '/') { - continue; - } - recoveredPath[i] = '\0'; - folderName = recoveredPath.substr(lastPos + 1, i); - lastPos = i; - auto [isExist, ret] = Access(recoveredPath); - if (!isExist && !Mkdir(recoveredPath)) { - HILOG_ERROR("Mkdirs fail for %{public}s ", recoveredPath.c_str()); - return false; - } - recoveredPath[i] = '/'; - } - return true; -} - static int GenerateNewFileName(string &destFile, const string &filePathName, int32_t index, const string &fileSuffix) { auto [isExist, ret] = Access(destFile); @@ -356,26 +327,26 @@ static bool GenerateFileInfoEntity(FileInfo& fileInfoEntity, string filterDirent fileInfoEntity.fileName = fileName; size_t uMode = SUPPORTS_READ | SUPPORTS_WRITE; - StatEntity statEntity; - if (GetStat(filterDirent, statEntity)) { - bool check = (statEntity.stat_.st_mode & S_IFMT) == S_IFDIR; - if (check) { - uMode |= REPRESENTS_DIR; - } else { - uMode |= REPRESENTS_FILE; - } - HILOG_DEBUG("ListFile: After filter mode = %{public}zu", uMode); + auto [ret, statReq] = GetStat(filterDirent); + if (ret != ERRNO_NOERR) { + HILOG_ERROR("Failed to get file stat, error: %{public}d", ret); + return false; + } + if ((statReq->statbuf.st_mode & S_IFMT) == S_IFDIR) { + uMode |= REPRESENTS_DIR; + } else { + uMode |= REPRESENTS_FILE; + } - fileInfoEntity.mode = static_cast(uMode); - fileInfoEntity.size = static_cast(statEntity.stat_.st_size); - fileInfoEntity.mtime = static_cast(statEntity.stat_.st_mtim.tv_sec); + fileInfoEntity.mode = static_cast(uMode); + fileInfoEntity.size = static_cast(statReq->statbuf.st_size); + fileInfoEntity.mtime = static_cast(statReq->statbuf.st_mtim.tv_sec); - try { - fileInfoEntity.ctime = static_cast(atoll(timeSlot.c_str()) / SECOND_TO_MILLISECOND); - } catch (...) { - HILOG_ERROR("GenerateFileInfoEntity: invalid timeSlot = %{public}s", timeSlot.c_str()); - return false; - } + try { + fileInfoEntity.ctime = static_cast(atoll(timeSlot.c_str()) / SECOND_TO_MILLISECOND); + } catch (...) { + HILOG_ERROR("GenerateFileInfoEntity: invalid timeSlot = %{public}s", timeSlot.c_str()); + return false; } return true; } @@ -395,12 +366,6 @@ napi_value FileTrashNExporter::ListFile(napi_env env, napi_callback_info info) return nullptr; } vector dirents; - unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; - if (!pNameList) { - NError(ENOMEM).ThrowErr(env); - HILOG_ERROR("Failed to request heap memory."); - return nullptr; - } int ret = RecursiveFunc(FileTrashNExporter::trashPath_, dirents); if (ret != ERRNO_NOERR) { NError(ENOMEM).ThrowErr(env); @@ -430,127 +395,95 @@ napi_value FileTrashNExporter::ListFile(napi_env env, napi_callback_info info) return CreateObjectArray(env, fileInfoList); } -static napi_value RecoverFile(napi_env env, const string &filePath) +static int RecoverFile(const string &filePath, const string &sourceFilePath) { - string sourceFilePath = FindSourceFilePath(filePath); - HILOG_INFO("RecoverFile: sourceFilePath = %{public}s", sourceFilePath.c_str()); - string newDestPath = sourceFilePath; - if (newDestPath.length() == 0 || !Mkdirs(sourceFilePath, false, newDestPath)) { - HILOG_ERROR("RecoverFile: Mkdirs failed"); - NError(EINVAL).ThrowErr(env); - return nullptr; + size_t slashPos = sourceFilePath.find_last_of("/"); + string parentPath = sourceFilePath.substr(0, slashPos); + auto [isExist, ret] = Access(parentPath); + if (!isExist) { + ret = Mkdirs(parentPath.c_str(), MULTIPLE); } - - int moveRet = MoveFile(filePath, newDestPath); - if (moveRet != ERRNO_NOERR) { - HILOG_ERROR("RecoverFile: MoveFile failed"); - NError(moveRet).ThrowErr(env); - return nullptr; + if (ret != ERRNO_NOERR) { + HILOG_ERROR("RecoverFile: Failed to create directories, error: %{public}d", errno); + return errno; } - // 文件已被移动,则如果前一层目录包含其他内容,则直接返回; - // 如果不包含,则需要一层层向父目录回退判断对应目录是否需要删除 - size_t slashPos = filePath.find_last_of("/"); - string parentPath = filePath.substr(0, slashPos); - int num = ScanDir(parentPath); - if (num == 0) { - auto err = RmDirent(GetToDeletePath(parentPath, env)); - if (err) { - err.ThrowErr(env); - return nullptr; - } - } - return NVal::CreateUndefined(env).val_; + return MoveFile(filePath, sourceFilePath); } -static int RecoverFilePart(vector filePathList, map dirPath2UpdatedNameMap) +static int RecoverDir(const string &dirPath, const string &sourceFilePath) { - // 处理文件 - for (size_t j = 0; j < filePathList.size(); j++) { - string filePath = filePathList[j]; - HILOG_INFO("RecoverFilePart: filePath = %{public}s", filePath.c_str()); - string sourceFilePath = FindSourceFilePath(filePath); - HILOG_INFO("RecoverFilePart: sourceFilePath = %{public}s", sourceFilePath.c_str()); - - size_t lastSlashPos = sourceFilePath.find_last_of("/"); - string fileName = sourceFilePath.substr(lastSlashPos + 1); - string sourceFilePathOnly = sourceFilePath.substr(0, lastSlashPos); - map::iterator iter = dirPath2UpdatedNameMap.find(sourceFilePathOnly); - if (iter != dirPath2UpdatedNameMap.end()) { - sourceFilePath = iter->second + "/" + fileName; + unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; + if (!pNameList) { + HILOG_ERROR("RecoverDir: Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(dirPath.c_str(), &(pNameList->namelist), FilterFunc, alphasort); + if (num < 0) { + HILOG_ERROR("RecoverDir: Failed to scan dir, error: %{public}d", errno); + return errno; + } + int ret = 0; + for (int i = 0; i < num; i++) { + if ((*(pNameList->namelist[i])).d_type == DT_REG) { + string filePath = dirPath + '/' + string(pNameList->namelist[i]->d_name); + string destFilePath = sourceFilePath + '/' + string(pNameList->namelist[i]->d_name); + ret = RecoverFile(filePath, destFilePath); + } else if ((*(pNameList->namelist[i])).d_type == DT_DIR) { + string pathTemp = dirPath; + pathTemp += '/' + string((*(pNameList->namelist[i])).d_name); + string destDirPath = sourceFilePath + '/' + string(pNameList->namelist[i]->d_name); + ret = RenameDir(pathTemp, destDirPath); } - int moveRet = MoveFile(filePath, sourceFilePath); - if (moveRet != ERRNO_NOERR) { - return moveRet; + if (ret != ERRNO_NOERR) { + HILOG_ERROR("RecoverDir: Failed to recursive get all dirents for %{public}d", ret); + return ret; } } return ERRNO_NOERR; } -static map MakeAndFindUpdateNameDir(vector filterDirPathList) -{ - map dirPath2UpdatedNameMap; - for (size_t j = 0; j < filterDirPathList.size(); j++) { - string dirPath = filterDirPathList[j]; - string sourceFilePath = FindSourceFilePath(dirPath); - HILOG_DEBUG("MakeAndFindUpdateNameDir: sourceFilePath = %{public}s", sourceFilePath.c_str()); - string newDestPath = sourceFilePath; - if (Mkdirs(sourceFilePath, true, newDestPath)) { - HILOG_DEBUG("MakeAndFindUpdateNameDir: newDestPath = %{public}s", newDestPath.c_str()); - if (newDestPath != sourceFilePath) { - dirPath2UpdatedNameMap.insert(make_pair(sourceFilePath, newDestPath)); - } - } - } - return dirPath2UpdatedNameMap; -} - -static napi_value RecoverDir(napi_env env, const string &dirPath) +static int RenameDir(const string &dirPath, const string &sourceFilePath) { - vector dirents; - unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; - if (!pNameList) { - HILOG_ERROR("RecoverDir: Failed to request heap memory."); - return nullptr; + auto [isExist, ret] = Access(sourceFilePath); + if (isExist) { + return RecoverDir(dirPath, sourceFilePath); + } else if (ret != ERRNO_NOERR) { + HILOG_ERROR("RenameDir: Failed to access source directory, error: %{public}d", ret); + return ret; } - int ret = RecursiveFunc(dirPath, dirents); - if (ret != ERRNO_NOERR) { - HILOG_ERROR("RecoverDir: Failed to Recursive Dir."); - return nullptr; + auto [atime, mtime, retGetTime] = GetFileTime(dirPath); + if (retGetTime != ERRNO_NOERR) { + HILOG_ERROR("RenameDir: Failed to get time properties of directory, error: %{public}d", retGetTime); + return retGetTime; } - dirents.emplace_back(dirPath); - // 区分目录和文件 - vector dirPathList; - vector filePathList; - for (size_t j = 0; j < dirents.size(); j++) { - string dirent = dirents[j]; - if (CheckDir(dirent)) { - dirPathList.emplace_back(dirent); - } else { - filePathList.emplace_back(dirent); - } + unique_ptr rename_req = { new uv_fs_t, fs_req_cleanup }; + if (!rename_req) { + HILOG_ERROR("RenameDir: Failed to request heap memory."); + return ENOMEM; } - - // 新建目录并获取因为存在同名目录修改过名称的目录 - map dirPath2UpdatedNameMap = MakeAndFindUpdateNameDir(dirPathList); - - // 处理文件部分 - auto retRecoveFilePart = RecoverFilePart(filePathList, dirPath2UpdatedNameMap); - if (retRecoveFilePart != ERRNO_NOERR) { - NError(retRecoveFilePart).ThrowErr(env); - HILOG_ERROR("RecoverFilePart: Failed to Recover File in Dir."); - return nullptr; + ret = uv_fs_rename(nullptr, rename_req.get(), dirPath.c_str(), sourceFilePath.c_str(), nullptr); + if (ret == -EXDEV) { + ret = Mkdir(sourceFilePath); + if (ret != ERRNO_NOERR) { + HILOG_ERROR("RenameDir: Failed to create the directory, error: %{public}d.", ret); + return ret; + } + ret = RecoverDir(dirPath, sourceFilePath); + if (ret != ERRNO_NOERR) { + return ret; + } + } else if (ret != ERRNO_NOERR) { + HILOG_ERROR("RenameDir: Failed to rename the directory, error: %{public}d", ret); + return ret; } - - // 删除目录 - auto err = RmDirent(GetToDeletePath(dirPath, env)); - if (err) { - err.ThrowErr(env); - return nullptr; + ret = SetFileTime(sourceFilePath, atime, mtime); + if (ret != ERRNO_NOERR) { + HILOG_ERROR("RenameDir: Failed to recover times for directory, error: %{public}d", ret); + return ret; } - - return NVal::CreateUndefined(env).val_; + return ERRNO_NOERR; } napi_value FileTrashNExporter::Recover(napi_env env, napi_callback_info info) @@ -567,46 +500,36 @@ napi_value FileTrashNExporter::Recover(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - bool succ = false; - unique_ptr uriPtr; - tie(succ, uriPtr, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + auto [succ, uriPtr, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); if (!succ) { NError(EINVAL).ThrowErr(env); return nullptr; } - string uriStr = uriPtr.get(); - HILOG_DEBUG("Recover: uriPtr.get() = %{public}s", uriStr.c_str()); - // 获取沙箱目录地址 - AppFileService::ModuleFileUri::FileUri fileUri(uriStr); + AppFileService::ModuleFileUri::FileUri fileUri(uriPtr.get()); string path = fileUri.GetPath(); - // 判断绝对路径 - if (!GetRealPath(path)) { + // 通过URI得到沙箱路径,判断是否是回收站路径 + if (path.find(FileTrashNExporter::trashPath_) == string::npos && access(path.c_str(), F_OK) != 0) { NError(EINVAL).ThrowErr(env); HILOG_ERROR("Recover: Invalid Path"); return nullptr; } - HILOG_DEBUG("Recover: path = %{public}s", path.c_str()); - // 判断是否是回收站路径 - if (path.find(FileTrashNExporter::trashPath_) == string::npos) { - NError(EINVAL).ThrowErr(env); - HILOG_ERROR("Recover: path = %{public}s is not Trash path", path.c_str()); + string sourceFilePath = FindSourceFilePath(path); + int ret = CheckDir(path) ? RenameDir(path, sourceFilePath) : RecoverFile(path, sourceFilePath); + if (ret) { + NError(ret).ThrowErr(env); + HILOG_ERROR("Recover: Failed to recover file or direcotries, error: %{public}d", ret); return nullptr; } - // 判断路径是否存在 - auto [isExist, ret] = Access(path); - if (!isExist) { - NError(EINVAL).ThrowErr(env); - HILOG_ERROR("Recover: Path is not exist"); + // 删除回收站空目录 + auto err = RmDirent(GetToDeletePath(path, env)); + if (err) { + err.ThrowErr(env); return nullptr; } - - if (!CheckDir(path)) { - return RecoverFile(env, path); - } - return RecoverDir(env, path); + return NVal::CreateUndefined(env).val_; } napi_value FileTrashNExporter::CompletelyDelete(napi_env env, napi_callback_info info) diff --git a/utils/file_util.h b/utils/file_util.h index 20de0023..191b8d6e 100644 --- a/utils/file_util.h +++ b/utils/file_util.h @@ -72,30 +72,16 @@ static void fs_req_cleanup(uv_fs_t* req) } } -static int CheckFsStatByPath(const string &path, uv_fs_t* req) -{ - int ret = uv_fs_stat(nullptr, req, path.c_str(), nullptr); - if (ret < 0) { - HILOG_ERROR("Failed to stat file with path"); - return ret; - } - return ERRNO_NOERR; -} - -static bool GetStat(const string &path, StatEntity &statEntity) +static tuple> GetStat(const string &path) { unique_ptr stat_req = { new (nothrow) uv_fs_t, fs_req_cleanup }; if (!stat_req) { HILOG_ERROR("Failed to request heap memory."); - return false; + return { ENOMEM, move(stat_req) }; } - auto err = CheckFsStatByPath(path, stat_req.get()); - if (!err) { - statEntity = StatEntity { stat_req->statbuf }; - return true; - } - return false; + int ret = uv_fs_stat(nullptr, stat_req.get(), path.c_str(), nullptr); + return { ret, move(stat_req) }; } static bool CheckDir(const string &path) @@ -125,50 +111,57 @@ static tuple Access(const string &path) return {isExist, ERRNO_NOERR}; } -static bool Mkdir(const string &path) +static int Mkdir(const string &path) { unique_ptr mkdir_req = { new uv_fs_t, fs_req_cleanup }; if (!mkdir_req) { HILOG_ERROR("Failed to request heap memory."); - return false; + return ENOMEM; } int ret = uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr); - if (ret < 0) { - HILOG_ERROR("Failed to create directory"); - return false; + return ret; +} + +static tuple GetFileTime(const string &src) +{ + auto [ret, statReq] = GetStat(src); + if (ret != ERRNO_NOERR) { + HILOG_ERROR("Failed to get file stat, error: %{public}d", ret); + return { 0, 0, ret }; } - if (ret == 0) { - return true; + double acTime = static_cast(statReq->statbuf.st_atim.tv_sec) + + static_cast(statReq->statbuf.st_atim.tv_nsec) / TIME_CONVERT_BASE; + double modTime = static_cast(statReq->statbuf.st_mtim.tv_sec) + + static_cast(statReq->statbuf.st_mtim.tv_nsec) / TIME_CONVERT_BASE; + + return { acTime, modTime, ERRNO_NOERR }; +} + +static int SetFileTime(const string &dest, double acTime, double modTime) +{ + unique_ptr utime_req = { new (nothrow) uv_fs_t, fs_req_cleanup }; + if (!utime_req) { + HILOG_ERROR("Failed to request heap memory."); + return ENOMEM; } - return false; + int ret = uv_fs_utime(nullptr, utime_req.get(), dest.c_str(), acTime, modTime, nullptr); + return ret; } static int CopyAndDeleteFile(const string &src, const string &dest) { // 获取源文件时间 - StatEntity statEntity; - if (!GetStat(src, statEntity)) { - HILOG_ERROR("Failed to get file stat."); - return EINVAL; + auto [acTime, modTime, ret] = GetFileTime(src); + if (ret != ERRNO_NOERR) { + HILOG_ERROR("Failed to get file stat, error: %{public}d", ret); + return ret; } - // 拼接秒数和纳秒数 - uint64_t acTimeLong = static_cast(statEntity.stat_.st_atim.tv_sec * TIME_CONVERT_BASE + - statEntity.stat_.st_atim.tv_nsec); - uint64_t modTimeLong = static_cast(statEntity.stat_.st_mtim.tv_sec * TIME_CONVERT_BASE + - statEntity.stat_.st_mtim.tv_nsec); - double acTime = static_cast(acTimeLong) / TIME_CONVERT_BASE; - double modTime = static_cast(modTimeLong) / TIME_CONVERT_BASE; - - int ret = 0; uv_fs_t copyfile_req; ret = uv_fs_copyfile(nullptr, ©file_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr); uv_fs_req_cleanup(©file_req); // 设置目标文件时间 - uv_fs_t utime_req; - uv_fs_utime(nullptr, &utime_req, dest.c_str(), acTime, modTime, nullptr); - uv_fs_req_cleanup(&utime_req); - + ret = SetFileTime(dest, acTime, modTime); if (ret < 0) { HILOG_ERROR("Failed to move file using copyfile interface."); return ret; -- Gitee