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 bfaf4a022454aae539ea0fe430bf70ef0b4b8eab..5a84d697b705fbcc3407d676ad677370093f4288 100644 --- a/interfaces/kits/native/trash/src/file_trash_n_exporter.cpp +++ b/interfaces/kits/native/trash/src/file_trash_n_exporter.cpp @@ -69,7 +69,7 @@ static string GetTimeSlotFromPath(const string &path) // 获取时间戳目录位置 size_t trashPathWithTimePrefixPos = realFilePathWithTime.find_first_of("/"); if (trashPathWithTimePrefixPos == string::npos) { - HILOG_ERROR("GetTimeSlotFromPath: Invalid path = %{public}s", path.c_str()); + HILOG_ERROR("GetTimeSlotFromPath: Invalid path"); return ""; } string timeSlot = realFilePathWithTime.substr(0, trashPathWithTimePrefixPos); @@ -77,6 +77,8 @@ static string GetTimeSlotFromPath(const string &path) return timeSlot; } +static int RecurMoveDir(const string &srcPath, const string &destPath); + static int RecursiveFunc(const string &path, vector &dirents) { unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; @@ -84,7 +86,6 @@ static int RecursiveFunc(const string &path, vector &dirents) HILOG_ERROR("Failed to request heap memory."); return ENOMEM; } - HILOG_DEBUG("RecursiveFunc: scandir path = %{public}s", path.c_str()); int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort); if (num < 0) { HILOG_ERROR("RecursiveFunc: Failed to scan dir"); @@ -99,7 +100,6 @@ static int RecursiveFunc(const string &path, vector &dirents) string pathTemp = pathInRecur; pathInRecur += '/' + string((*(pNameList->namelist[i])).d_name); // check if path include TRASH_SUB_DIR + "/", need to add it into dirents - HILOG_DEBUG("RecursiveFunc: pathTemp = %{public}s", pathTemp.c_str()); string timeSlot = GetTimeSlotFromPath(pathTemp); if (!timeSlot.empty() && pathInRecur.rfind(TRASH_SUB_DIR + timeSlot + "/") != string::npos) { // Only filter previous dir is TRASH_SUB_DIR @@ -156,9 +156,8 @@ static napi_value CreateObjectArray(napi_env env, vector result) return fileInfoResultArray; } -static string FindSourceFilePath(const string &path) +static string FindSourceFilePath(const string &path, bool parentOnly) { - HILOG_INFO("FindSourceFilePath: curFilePath = %{public}s", path.c_str()); size_t slashSize = 1; // 获取/trash目录位置 size_t trashPathPrefixPos = path.find(TRASH_PATH); @@ -182,17 +181,19 @@ static string FindSourceFilePath(const string &path) HILOG_ERROR("FindSourceFilePath: : Invalid Path No Trash Sub Path"); return ""; } - string realFilePathPrefix = realFilePath.substr(0, pos); + string realFilePathPrefix = "/" + realFilePath.substr(0, pos); + if (parentOnly) { + return realFilePathPrefix; + } string realFileName = realFilePath.substr(pos + TRASH_SUB_DIR.length() + timeSlot.length() + slashSize); - realFilePath = "/" + realFilePathPrefix + realFileName; - HILOG_INFO("FindSourceFilePath: realFilePath After = %{public}s", realFilePath.c_str()); + realFilePath = realFilePathPrefix + realFileName; return realFilePath; } -static bool Mkdirs(const string &path, bool isDir, string &newRecoveredPath) +static bool Mkdirs(const string &path, bool isDir) { - HILOG_INFO("Mkdirs: path = %{public}s", path.c_str()); + HILOG_INFO("Mkdirs start"); string recoveredPath = path; string folderName = ""; size_t lastPos = 0; @@ -213,7 +214,7 @@ static bool Mkdirs(const string &path, bool isDir, string &newRecoveredPath) lastPos = i; auto [isExist, ret] = Access(recoveredPath); if (!isExist && !Mkdir(recoveredPath)) { - HILOG_ERROR("Mkdirs fail for %{public}s ", recoveredPath.c_str()); + HILOG_ERROR("Mkdirs fail"); return false; } recoveredPath[i] = '/'; @@ -252,7 +253,7 @@ static string GenerateNewFileNameNoSuffix(const string &destFile, int32_t distin return ""; } -static bool MoveFile(const string &srcFile, const string &destFile) +static int MoveFile(const string &srcFile, const string &destFile) { // 判断目的文件是否存在 auto [isExist, ret] = Access(destFile); @@ -262,9 +263,14 @@ static bool MoveFile(const string &srcFile, const string &destFile) size_t slashPos = destFile.find_last_of("/"); if (slashPos == string::npos) { HILOG_ERROR("MoveFile: : Invalid Path"); - return false; + return E_INVAL; + } + // 识别文件后缀分隔符 + size_t suffixPos = destFile.find_last_of('.'); + if (suffixPos < slashPos) { + // 识别的文件后缀分隔符必须在文件部分 + suffixPos = string::npos; } - size_t suffixPos = destFile.find_first_of('.', slashPos); HILOG_DEBUG("MoveFile: slashPos = %{public}zu", slashPos); HILOG_DEBUG("MoveFile: suffixPos = %{public}zu", suffixPos); string newDestFile = destFile; @@ -276,49 +282,103 @@ static bool MoveFile(const string &srcFile, const string &destFile) } else { string newPrefix = destFile.substr(0, suffixPos) + " "; string newSuffix = destFile.substr(suffixPos); - HILOG_DEBUG("MoveFile: newPrefix = %{public}s", newPrefix.c_str()); - HILOG_DEBUG("MoveFile: newSuffix = %{public}s", newSuffix.c_str()); // 查看加上数字后缀后文件是否已经存在,若存在,需要重新获取 newDestFile = GenerateNewFileNameWithSuffix(newPrefix + to_string(distinctSuffixIndex) + newSuffix, distinctSuffixIndex, newPrefix, newSuffix); } - HILOG_INFO("MoveFile: newDestFile = %{public}s", newDestFile.c_str()); + HILOG_INFO("MoveFile Exist"); return RenameFile(srcFile, newDestFile); } else if (ret == ERRNO_NOERR) { return RenameFile(srcFile, destFile); } - HILOG_ERROR("MoveFile: : Invalid Path"); - return false; + HILOG_ERROR("MoveFile: Invalid Path"); + return E_INVAL; +} + +static int RenameDir(const string &src, const string &dest) +{ + HILOG_INFO("RenameDir Start"); + filesystem::path destPath(dest); + if (!filesystem::exists(destPath)) { + filesystem::path srcPath(src); + std::error_code errCode; + filesystem::rename(srcPath, destPath, errCode); + if (errCode.value() == EXDEV) { + HILOG_ERROR("RenameDir: Failed to rename file due to EXDEV"); + if (filesystem::create_directory(destPath, errCode)) { + return RecurMoveDir(src, dest); + } else { + HILOG_ERROR("RenameDir: Failed to create directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + } + if (errCode.value() != 0) { + HILOG_ERROR("RenameDir: Failed to rename file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + } else { + return RecurMoveDir(src, dest); + } + return ERRNO_NOERR; +} + + +static int RecurMoveDir(const string &srcPath, const string &destPath) +{ + unique_ptr ptr = {new struct NameListArg, Deleter}; + if (!ptr) { + HILOG_ERROR("RecurMoveDir: Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(srcPath.c_str(), &(ptr->namelist), FilterFunc, alphasort); + ptr->direntNum = num; + for (int i = 0; i < num; i++) { + if ((ptr->namelist[i])->d_type == DT_DIR) { + string srcTemp = srcPath + '/' + string((ptr->namelist[i])->d_name); + string destTemp = destPath + '/' + string((ptr->namelist[i])->d_name); + int res = RenameDir(srcTemp, destTemp); + if (res != ERRNO_NOERR) { + return res; + } + } else { + string src = srcPath + '/' + string((ptr->namelist[i])->d_name); + string dest = destPath + '/' + string((ptr->namelist[i])->d_name); + int res = MoveFile(src, dest); + if (res != ERRNO_NOERR) { + HILOG_ERROR("RecurMoveDir: Failed to rename file for error %{public}d", res); + return res; + } + } + } + return ERRNO_NOERR; } static string RecurCheckIfOnlyContentInDir(const string &path, size_t trashWithTimePos, const string &trashWithTimePath) { - HILOG_INFO("RecurCheckIfOnlyContentInDir: path = %{public}s", path.c_str()); + HILOG_INFO("RecurCheckIfOnlyContentInDir start"); size_t slashPos = path.find_last_of("/"); if (slashPos <= trashWithTimePos) { HILOG_DEBUG("RecurCheckIfOnlyContentInDir: slashPos = %{public}zu", slashPos); return trashWithTimePath; } string parentPath = path.substr(0, slashPos); - HILOG_DEBUG("RecurCheckIfOnlyContentInDir: parentPath = %{public}s", parentPath.c_str()); int num = ScanDir(parentPath); - HILOG_DEBUG("RecurCheckIfOnlyContentInDir: num = %{public}d", num); + HILOG_INFO("RecurCheckIfOnlyContentInDir: num = %{public}d", num); if (num > 1) { // 同一时间戳目录下存在多个删除项,则不论是还原后的删除还是彻底删除,仅需删除该项 - HILOG_DEBUG("RecurCheckIfOnlyContentInDir: find other items in current dir"); return path; } else if (num == 1) { // 需要向上一层目录判断 return RecurCheckIfOnlyContentInDir(parentPath, trashWithTimePos, trashWithTimePath); } else { - HILOG_ERROR("RecurCheckIfOnlyContentInDir: invalid path = %{public}s", path.c_str()); + HILOG_ERROR("RecurCheckIfOnlyContentInDir: invalid path"); } return nullptr; } static string GetToDeletePath(const string &toDeletePath, napi_env env) { - HILOG_INFO("GetToDeletePath: toDeletePath = %{public}s", toDeletePath.c_str()); + HILOG_INFO("GetToDeletePath start"); // 判断是否为有效回收站路径 size_t slashSize = 1; // 获取/Trash目录位置 @@ -343,7 +403,7 @@ static string GetToDeletePath(const string &toDeletePath, napi_env env) static bool GenerateFileInfoEntity(FileInfo& fileInfoEntity, string filterDirent, string timeSlot) { - string realFilePath = FindSourceFilePath(filterDirent); + string realFilePath = FindSourceFilePath(filterDirent, false); size_t lastSlashPos = filterDirent.find_last_of("/"); if (lastSlashPos == string::npos) { HILOG_ERROR("GenerateFileInfoEntity: invalid path"); @@ -433,139 +493,81 @@ napi_value FileTrashNExporter::ListFile(napi_env env, napi_callback_info info) static napi_value RecoverFile(napi_env env, const string &filePath) { - string sourceFilePath = FindSourceFilePath(filePath); - HILOG_INFO("RecoverFile: sourceFilePath = %{public}s", sourceFilePath.c_str()); - string newDestPath = sourceFilePath; - if (newDestPath.length() != 0 && Mkdirs(sourceFilePath, false, newDestPath)) { - MoveFile(filePath, newDestPath); - } - - // 文件已被移动,则如果前一层目录包含其他内容,则直接返回; - // 如果不包含,则需要一层层向父目录回退判断对应目录是否需要删除 - 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_; -} - -static void RecoverFilePart(vector filePathList, map dirPath2UpdatedNameMap) -{ - // 处理文件 - 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; - } - MoveFile(filePath, sourceFilePath); - } -} - -static vector FilterDirsNoContains(vector dirPathList) -{ - //先处理目录,仅保留不互相包含的目录(取子目录较深的) - vector filterDirPathList; - for (size_t j = 0; j < dirPathList.size(); j++) { - string dirPath = dirPathList[j]; - bool isIncluded = false; - for (size_t k = 0; k < filterDirPathList.size(); k++) { - string filterDirPath = filterDirPathList[k]; - if (StartsWith(filterDirPath, dirPath)) { - isIncluded = true; - break; - } - } - if (!isIncluded) { - filterDirPathList.emplace_back(dirPath); - } - } - return filterDirPathList; -} - -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)); + HILOG_INFO("RecoverFile start"); + string sourceFilePath = FindSourceFilePath(filePath, false); + // 判断还原文件所在目录是否存在,不存在则新创建,然后移动文件 + if (Mkdirs(sourceFilePath, false) && (MoveFile(filePath, sourceFilePath) == ERRNO_NOERR)) { + // 文件已被移动,则如果前一层目录包含其他内容,则直接返回; + // 如果不包含,则需要一层层向父目录回退判断对应目录是否需要删除 + 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_; + } else { + HILOG_ERROR("RecoverFile fail"); + NError(EINVAL).ThrowErr(env); + return nullptr; } - return dirPath2UpdatedNameMap; } static napi_value RecoverDir(napi_env env, const string &dirPath) { - vector dirents; - unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; - if (!pNameList) { - HILOG_ERROR("RecoverDir: Failed to request heap memory."); + HILOG_INFO("RecoverDir start"); + // 获取待还原目录所在父目录 + string parentPath = FindSourceFilePath(dirPath, true); + if (parentPath.length() == 0) { + HILOG_ERROR("RecoverDir fail"); + NError(EINVAL).ThrowErr(env); return nullptr; } - int ret = RecursiveFunc(dirPath, dirents); - if (ret != ERRNO_NOERR) { - HILOG_ERROR("RecoverDir: Failed to Recursive Dir."); + size_t lastSlashPos = dirPath.rfind('/'); + if (lastSlashPos == std::string::npos) { + NError(EINVAL).ThrowErr(env); return nullptr; } - 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); + string dirName = dirPath.substr(lastSlashPos); + string destStr = parentPath + dirName; + + // 检查父目录是否存在,否则创建,然后移动目录 + if (Mkdirs(parentPath, true) && (RenameDir(dirPath, destStr) == ERRNO_NOERR)) { + // 删除目录 + auto [isExist, ret] = Access(dirPath); + if (isExist) { + // 待还原目录存在 + auto err = RmDirent(GetToDeletePath(dirPath, env)); + if (err) { + err.ThrowErr(env); + return nullptr; + } } else { - filePathList.emplace_back(dirent); + // 待还原目录已被移动,则判断其父目录 + size_t slashPos = dirPath.find_last_of("/"); + string upperPath = dirPath.substr(0, slashPos); + int num = ScanDir(upperPath); + // 目录已被移动,则如果前一层目录包含其他内容,则直接返回; + // 如果不包含,则需要一层层向父目录回退判断对应目录是否需要删除 + if (num != 0) { + return NVal::CreateUndefined(env).val_; + } + auto err = RmDirent(GetToDeletePath(upperPath, env)); + if (err) { + err.ThrowErr(env); + return nullptr; + } } - } - // 目录从长到短排序 - sort(dirPathList.begin(), dirPathList.end(), [&](const string &a, const string &b) { - return a.length() > b.length(); - }); - - // 先处理目录,仅保留不互相包含的目录(取子目录较深的) - vector filterDirPathList = FilterDirsNoContains(dirPathList); - if (filterDirPathList.size() == 0) { - HILOG_ERROR("RecoverDir: NO valid dirs found"); - return nullptr; - } - - // 新建目录并获取因为存在同名目录修改过名称的目录 - map dirPath2UpdatedNameMap = MakeAndFindUpdateNameDir(filterDirPathList); - - // 处理文件部分 - RecoverFilePart(filePathList, dirPath2UpdatedNameMap); - - // 删除目录 - auto err = RmDirent(GetToDeletePath(dirPath, env)); - if (err) { - err.ThrowErr(env); + return NVal::CreateUndefined(env).val_; + } else { + HILOG_ERROR("RecoverDir fail"); + NError(EINVAL).ThrowErr(env); return nullptr; } - - return NVal::CreateUndefined(env).val_; } napi_value FileTrashNExporter::Recover(napi_env env, napi_callback_info info) @@ -590,7 +592,6 @@ napi_value FileTrashNExporter::Recover(napi_env env, napi_callback_info info) return nullptr; } string uriStr = uriPtr.get(); - HILOG_DEBUG("Recover: uriPtr.get() = %{public}s", uriStr.c_str()); // 获取沙箱目录地址 AppFileService::ModuleFileUri::FileUri fileUri(uriStr); @@ -601,12 +602,10 @@ napi_value FileTrashNExporter::Recover(napi_env env, napi_callback_info info) HILOG_ERROR("Recover: Invalid Path"); return nullptr; } - HILOG_DEBUG("Recover: path = %{public}s", path.c_str()); // 判断是否是回收站路径 if (path.find(TRASH_PATH) == string::npos) { NError(EINVAL).ThrowErr(env); - HILOG_ERROR("Recover: path = %{public}s is not Trash path", path.c_str()); return nullptr; } @@ -648,7 +647,6 @@ napi_value FileTrashNExporter::CompletelyDelete(napi_env env, napi_callback_info } string uriStr = uriPtr.get(); - HILOG_DEBUG("Recover: uriPtr.get() = %{public}s", uriStr.c_str()); // 获取沙箱目录地址 AppFileService::ModuleFileUri::FileUri fileUri(uriStr); @@ -659,12 +657,11 @@ napi_value FileTrashNExporter::CompletelyDelete(napi_env env, napi_callback_info HILOG_ERROR("Recover: Invalid Path"); return nullptr; } - HILOG_DEBUG("Recover: path = %{public}s", path.c_str()); // 判断是否是回收站路径 if (path.find(TRASH_PATH) == string::npos) { NError(EINVAL).ThrowErr(env); - HILOG_ERROR("Recover: path = %{public}s is not Trash path", path.c_str()); + HILOG_ERROR("Recover: path is not Trash path"); return nullptr; } diff --git a/utils/file_util.h b/utils/file_util.h index d7c36e08e9b868be1116dba1e6933b3d1677b983..affee95d002911446923ef1ac00ecd8024a2f366 100644 --- a/utils/file_util.h +++ b/utils/file_util.h @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -46,11 +47,6 @@ struct StatEntity { uv_stat_t stat_; }; -static bool StartsWith(const string& str, const string prefix) -{ - return (str.rfind(prefix, 0) == 0); -} - static void Deleter(struct NameListArg *arg) { for (int i = 0; i < arg->direntNum; i++) {