• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "file_trash_n_exporter.h"
17 
18 #include <ctime>
19 
20 #include "access_token.h"
21 #include "accesstoken_kit.h"
22 #include "file_access_framework_errno.h"
23 #include "file_info.h"
24 #include "file_uri.h"
25 #include "file_util.h"
26 #include "ipc_skeleton.h"
27 
28 namespace OHOS {
29 namespace Trash {
30 namespace {
31     const std::string FILE_ACCESS_PERMISSION = "ohos.permission.FILE_ACCESS_MANAGER";
32 }
33 
34 using namespace FileManagement::LibN;
35 using namespace FileManagement;
36 using namespace std;
37 
CheckCallingPermission(const std::string & permission)38 static bool CheckCallingPermission(const std::string &permission)
39 {
40     Security::AccessToken::AccessTokenID tokenCaller = IPCSkeleton::GetCallingTokenID();
41     int res = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenCaller, permission);
42     if (res != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
43         HILOG_ERROR("FileTrashNExporter::CheckCallingPermission have no fileAccess permission");
44         return false;
45     }
46     return true;
47 }
48 
GetRealPath(string & path)49 static bool GetRealPath(string &path)
50 {
51     unique_ptr<char[]> absPath = make_unique<char[]>(PATH_MAX + 1);
52     if (realpath(path.c_str(), absPath.get()) == nullptr) {
53         return false;
54     }
55     path = absPath.get();
56     return true;
57 }
58 
GetTimeSlotFromPath(const string & path)59 static string GetTimeSlotFromPath(const string &path)
60 {
61     int slashSize = 1;
62     // 获取时间戳
63     size_t trashPathPrefixPos = path.find(TRASH_PATH);
64     size_t expectTimeSlotStartPos = trashPathPrefixPos + TRASH_PATH.length() + slashSize;
65     if (expectTimeSlotStartPos >= path.length()) {
66         return "";
67     }
68     string realFilePathWithTime = path.substr(trashPathPrefixPos + TRASH_PATH.length() + slashSize);
69     // 获取时间戳目录位置
70     size_t trashPathWithTimePrefixPos = realFilePathWithTime.find_first_of("/");
71     if (trashPathWithTimePrefixPos == string::npos) {
72         HILOG_ERROR("GetTimeSlotFromPath: Invalid path = %{public}s", path.c_str());
73         return "";
74     }
75     string timeSlot = realFilePathWithTime.substr(0, trashPathWithTimePrefixPos);
76     HILOG_DEBUG("GetTimeSlotFromPath: timeSlot = %{public}s", timeSlot.c_str());
77     return timeSlot;
78 }
79 
RecursiveFunc(const string & path,vector<string> & dirents)80 static int RecursiveFunc(const string &path, vector<string> &dirents)
81 {
82     unique_ptr<struct NameListArg, decltype(Deleter)*> pNameList = { new (nothrow) struct NameListArg, Deleter };
83     if (!pNameList) {
84         HILOG_ERROR("Failed to request heap memory.");
85         return ENOMEM;
86     }
87     HILOG_DEBUG("RecursiveFunc: scandir path = %{public}s", path.c_str());
88     int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort);
89     if (num < 0) {
90         HILOG_ERROR("RecursiveFunc: Failed to scan dir");
91         return errno;
92     }
93     pNameList->direntNum = num;
94     string pathInRecur = path;
95     for (int i = 0; i < num; i++) {
96         if ((*(pNameList->namelist[i])).d_type == DT_REG) {
97             dirents.emplace_back(path + '/' + pNameList->namelist[i]->d_name);
98         } else if ((*(pNameList->namelist[i])).d_type == DT_DIR) {
99             string pathTemp = pathInRecur;
100             pathInRecur += '/' + string((*(pNameList->namelist[i])).d_name);
101             // check if path include TRASH_SUB_DIR + "/", need to add it into dirents
102             HILOG_DEBUG("RecursiveFunc: pathTemp = %{public}s", pathTemp.c_str());
103             string timeSlot = GetTimeSlotFromPath(pathTemp);
104             if (!timeSlot.empty() && pathInRecur.rfind(TRASH_SUB_DIR + timeSlot + "/") != string::npos) {
105                 // Only filter previous dir is TRASH_SUB_DIR
106                 dirents.emplace_back(pathInRecur);
107             }
108             int ret = RecursiveFunc(pathInRecur, dirents);
109             if (ret != ERRNO_NOERR) {
110                 HILOG_ERROR("RecursiveFunc: Failed to recursive get all dirents for %{public}d", ret);
111                 return ret;
112             }
113             pathInRecur = pathTemp;
114         }
115     }
116     return ERRNO_NOERR;
117 }
118 
CreateObjectArray(napi_env env,vector<FileInfo> result)119 static napi_value CreateObjectArray(napi_env env, vector<FileInfo> result)
120 {
121     uint32_t status = napi_ok;
122     napi_value fileInfoResultArray = nullptr;
123     status = napi_create_array_with_length(env, result.size(), &fileInfoResultArray);
124     if (status != napi_ok) {
125         HILOG_ERROR("Create napi array fail");
126         return nullptr;
127     }
128 
129     for (size_t i = 0; i < result.size(); i++) {
130         FileInfo &tmpResult = result.at(i);
131         napi_value resultVal;
132         status |= napi_create_object(env, &resultVal);
133         napi_value tmpVal;
134         status |= napi_create_string_utf8(env, tmpResult.uri.c_str(), tmpResult.uri.length(), &tmpVal);
135         status |= napi_set_named_property(env, resultVal, "uri", tmpVal);
136         status |= napi_create_string_utf8(env, tmpResult.srcPath.c_str(), tmpResult.srcPath.length(), &tmpVal);
137         status |= napi_set_named_property(env, resultVal, "srcPath", tmpVal);
138         status |= napi_create_string_utf8(env, tmpResult.fileName.c_str(), tmpResult.fileName.length(), &tmpVal);
139         status |= napi_set_named_property(env, resultVal, "fileName", tmpVal);
140         status |= napi_create_int64(env, tmpResult.mode, &tmpVal);
141         status |= napi_set_named_property(env, resultVal, "mode", tmpVal);
142         status |= napi_create_int64(env, tmpResult.mode, &tmpVal);
143         status |= napi_set_named_property(env, resultVal, "mode", tmpVal);
144         status |= napi_create_int64(env, tmpResult.size, &tmpVal);
145         status |= napi_set_named_property(env, resultVal, "size", tmpVal);
146         status |= napi_create_int64(env, tmpResult.mtime, &tmpVal);
147         status |= napi_set_named_property(env, resultVal, "mtime", tmpVal);
148         status |= napi_create_int64(env, tmpResult.ctime, &tmpVal);
149         status |= napi_set_named_property(env, resultVal, "ctime", tmpVal);
150         status |= napi_set_element(env, fileInfoResultArray, i, resultVal);
151         if (status != napi_ok) {
152             HILOG_ERROR("Create CopyResult object error");
153             return nullptr;
154         }
155     }
156     return fileInfoResultArray;
157 }
158 
FindSourceFilePath(const string & path)159 static string FindSourceFilePath(const string &path)
160 {
161     HILOG_INFO("FindSourceFilePath: curFilePath = %{public}s", path.c_str());
162     size_t slashSize = 1;
163     // 获取/trash目录位置
164     size_t trashPathPrefixPos = path.find(TRASH_PATH);
165     if (trashPathPrefixPos == string::npos) {
166         HILOG_ERROR("FindSourceFilePath: Invalid Path No Trash Path");
167         return "";
168     }
169     size_t timeSLotStartPos = trashPathPrefixPos + TRASH_PATH.length() + slashSize;
170     string realFilePathWithTime = path.substr(timeSLotStartPos);
171     // 获取时间戳目录位置
172     size_t trashPathWithTimePrefixPos = realFilePathWithTime.find_first_of("/");
173     if (trashPathWithTimePrefixPos == string::npos) {
174         HILOG_ERROR("FindSourceFilePath: : Invalid Path No timestamp");
175         return "";
176     }
177     // 获取时间戳
178     string timeSlot = realFilePathWithTime.substr(0, trashPathWithTimePrefixPos);
179     string realFilePath = realFilePathWithTime.substr(trashPathWithTimePrefixPos + slashSize);
180     size_t pos = realFilePath.rfind(TRASH_SUB_DIR + timeSlot + "/");
181     if (pos == string::npos) {
182         HILOG_ERROR("FindSourceFilePath: : Invalid Path No Trash Sub Path");
183         return "";
184     }
185     string realFilePathPrefix = realFilePath.substr(0, pos);
186     string realFileName = realFilePath.substr(pos + TRASH_SUB_DIR.length() +
187         timeSlot.length() + slashSize);
188     realFilePath = "/" + realFilePathPrefix + realFileName;
189     HILOG_INFO("FindSourceFilePath: realFilePath After = %{public}s", realFilePath.c_str());
190     return realFilePath;
191 }
192 
Mkdirs(const string & path,bool isDir,string & newRecoveredPath)193 static bool Mkdirs(const string &path, bool isDir, string &newRecoveredPath)
194 {
195     HILOG_INFO("Mkdirs: path = %{public}s", path.c_str());
196     string recoveredPath = path;
197     string folderName = "";
198     size_t lastPos = 0;
199     if (recoveredPath.length() == 0) {
200         return false;
201     }
202     // if argument uri is dir, then add "/"
203     if (isDir) {
204         recoveredPath = recoveredPath + "/";
205     }
206 
207     for (size_t i = 1; i < recoveredPath.length(); ++i) {
208         if (recoveredPath[i] != '/') {
209             continue;
210         }
211         recoveredPath[i] = '\0';
212         folderName = recoveredPath.substr(lastPos + 1, i);
213         lastPos = i;
214         auto [isExist, ret] = Access(recoveredPath);
215         if (!isExist && !Mkdir(recoveredPath)) {
216             HILOG_ERROR("Mkdirs fail for %{public}s ", recoveredPath.c_str());
217             return false;
218         }
219         recoveredPath[i] = '/';
220     }
221     return true;
222 }
223 
GenerateNewFileNameWithSuffix(const string & destFile,int32_t distinctSuffixIndex,const string & newPrefix,const string & newSuffix)224 static string GenerateNewFileNameWithSuffix(const string &destFile, int32_t distinctSuffixIndex,
225     const string &newPrefix, const string &newSuffix)
226 {
227     // 处理存在后缀名的文件
228     auto [isExist, ret] = Access(destFile);
229     if (isExist) {
230         distinctSuffixIndex += 1;
231         string newDestFile = newPrefix + to_string(distinctSuffixIndex) + newSuffix;
232         return GenerateNewFileNameWithSuffix(newDestFile, distinctSuffixIndex, newPrefix, newSuffix);
233     } else if (!isExist && (ret == ERRNO_NOERR)) {
234         HILOG_DEBUG("GenerateNewFileNameWithSuffix: destFile = %{public}s", destFile.c_str());
235         return destFile;
236     }
237     return "";
238 }
239 
GenerateNewFileNameNoSuffix(const string & destFile,int32_t distinctSuffixIndex,const string & newPrefix)240 static string GenerateNewFileNameNoSuffix(const string &destFile, int32_t distinctSuffixIndex, const string &newPrefix)
241 {
242     // 处理不存在后缀名的文件
243     auto [isExist, ret] = Access(destFile);
244     if (isExist) {
245         distinctSuffixIndex += 1;
246         string newDestFile = newPrefix + to_string(distinctSuffixIndex);
247         return GenerateNewFileNameNoSuffix(newDestFile, distinctSuffixIndex, newPrefix);
248     } else if (!isExist && (ret == ERRNO_NOERR)) {
249         HILOG_DEBUG("GenerateNewFileNameNoSuffix: destFile = %{public}s", destFile.c_str());
250         return destFile;
251     }
252     return "";
253 }
254 
MoveFile(const string & srcFile,const string & destFile)255 static bool MoveFile(const string &srcFile, const string &destFile)
256 {
257     // 判断目的文件是否存在
258     auto [isExist, ret] = Access(destFile);
259     if (isExist) {
260         // 存在同名文件,需要加上数字后缀区分
261         // 获取文件前一级目录'/' 位置,从这个位置出发寻找文件后缀分隔符'.'
262         size_t slashPos = destFile.find_last_of("/");
263         if (slashPos == string::npos) {
264             HILOG_ERROR("MoveFile: : Invalid Path");
265             return false;
266         }
267         size_t suffixPos = destFile.find_first_of('.', slashPos);
268         HILOG_DEBUG("MoveFile: slashPos = %{public}zu", slashPos);
269         HILOG_DEBUG("MoveFile: suffixPos = %{public}zu", suffixPos);
270         string newDestFile = destFile;
271         int32_t distinctSuffixIndex = 1;
272         if (suffixPos == string::npos) {
273             string newPrefix = newDestFile + " ";
274             newDestFile = newPrefix + to_string(distinctSuffixIndex);
275             newDestFile = GenerateNewFileNameNoSuffix(newDestFile, distinctSuffixIndex, newPrefix);
276         } else {
277             string newPrefix = destFile.substr(0, suffixPos) + " ";
278             string newSuffix =  destFile.substr(suffixPos);
279             HILOG_DEBUG("MoveFile: newPrefix = %{public}s", newPrefix.c_str());
280             HILOG_DEBUG("MoveFile: newSuffix = %{public}s", newSuffix.c_str());
281             // 查看加上数字后缀后文件是否已经存在,若存在,需要重新获取
282             newDestFile = GenerateNewFileNameWithSuffix(newPrefix + to_string(distinctSuffixIndex) + newSuffix,
283                 distinctSuffixIndex, newPrefix, newSuffix);
284         }
285         HILOG_INFO("MoveFile: newDestFile = %{public}s", newDestFile.c_str());
286         return RenameFile(srcFile, newDestFile);
287     } else if (!isExist && (ret == ERRNO_NOERR)) {
288         return RenameFile(srcFile, destFile);
289     }
290     HILOG_ERROR("MoveFile: : Invalid Path");
291     return false;
292 }
293 
RecurCheckIfOnlyContentInDir(const string & path,size_t trashWithTimePos,const string & trashWithTimePath)294 static string RecurCheckIfOnlyContentInDir(const string &path, size_t trashWithTimePos, const string &trashWithTimePath)
295 {
296     HILOG_INFO("RecurCheckIfOnlyContentInDir: path = %{public}s", path.c_str());
297     size_t slashPos = path.find_last_of("/");
298     if (slashPos <= trashWithTimePos) {
299         HILOG_DEBUG("RecurCheckIfOnlyContentInDir: slashPos = %{public}zu", slashPos);
300         return trashWithTimePath;
301     }
302     string parentPath = path.substr(0, slashPos);
303     HILOG_DEBUG("RecurCheckIfOnlyContentInDir: parentPath = %{public}s", parentPath.c_str());
304     int num = ScanDir(parentPath);
305     HILOG_DEBUG("RecurCheckIfOnlyContentInDir: num = %{public}d", num);
306     if (num > 1) {
307         // 同一时间戳目录下存在多个删除项,则不论是还原后的删除还是彻底删除,仅需删除该项
308         HILOG_DEBUG("RecurCheckIfOnlyContentInDir: find other items in current dir");
309         return path;
310     } else if (num == 1) {
311         // 需要向上一层目录判断
312         return RecurCheckIfOnlyContentInDir(parentPath, trashWithTimePos, trashWithTimePath);
313     } else {
314         HILOG_ERROR("RecurCheckIfOnlyContentInDir: invalid path = %{public}s", path.c_str());
315     }
316     return nullptr;
317 }
318 
GetToDeletePath(const string & toDeletePath,napi_env env)319 static string GetToDeletePath(const string &toDeletePath, napi_env env)
320 {
321     HILOG_INFO("GetToDeletePath: toDeletePath = %{public}s", toDeletePath.c_str());
322     // 判断是否为有效回收站路径
323     size_t slashSize = 1;
324     // 获取/Trash目录位置
325     size_t trashPathPrefixPos = toDeletePath.find(TRASH_PATH);
326     if (trashPathPrefixPos == string::npos ||
327         trashPathPrefixPos + TRASH_PATH.length() + slashSize >= toDeletePath.length()) {
328         NError(EINVAL).ThrowErr(env);
329         return nullptr;
330     }
331     string realFilePathWithTime = toDeletePath.substr(trashPathPrefixPos + TRASH_PATH.length() + slashSize);
332     // 获取时间戳目录位置
333     size_t trashPathWithTimePrefixPos = realFilePathWithTime.find_first_of("/");
334     size_t realTimeDirPos = trashPathPrefixPos + TRASH_PATH.length() +
335         slashSize + trashPathWithTimePrefixPos;
336     // 回收站下一级的时间戳目录
337     string trashWithTimePath = toDeletePath.substr(0, realTimeDirPos);
338 
339     // 从待删除目录开始向内层遍历父目录,判断父目录是否仅有一个子目录,如果是则继续向前查找,直到时间戳目录为止;
340     // 如果不是仅有一个子目录,则待删除目录即子目录
341     return RecurCheckIfOnlyContentInDir(toDeletePath, realTimeDirPos, trashWithTimePath);
342 }
343 
GenerateFileInfoEntities(vector<string> filterDirents)344 static vector<FileInfo> GenerateFileInfoEntities(vector<string> filterDirents)
345 {
346     vector<FileInfo> fileInfoList;
347     for (size_t k = 0; k < filterDirents.size(); k++) {
348         string filterDirent = filterDirents[k];
349         HILOG_INFO("ListFile: After filter dirent  = %{public}s", filterDirent.c_str());
350 
351         string realFilePath = FindSourceFilePath(filterDirent);
352         HILOG_INFO("ListFile: After filter realFilePath  = %{public}s", realFilePath.c_str());
353         size_t lastSlashPos = filterDirent.find_last_of("/");
354         string fileName = filterDirent.substr(lastSlashPos + 1);
355 
356         FileInfo fileInfoEntity;
357         fileInfoEntity.uri = URI_PATH_PREFIX + filterDirent;
358         fileInfoEntity.srcPath = URI_PATH_PREFIX + realFilePath;
359         fileInfoEntity.fileName = fileName;
360 
361         int32_t mode = SUPPORTS_READ | SUPPORTS_WRITE;
362         StatEntity statEntity;
363         if (GetStat(filterDirent, statEntity)) {
364             bool check = (statEntity.stat_.st_mode & S_IFMT) == S_IFDIR;
365             if (check) {
366                 mode |= REPRESENTS_DIR;
367             } else {
368                 mode |= REPRESENTS_FILE;
369             }
370             HILOG_DEBUG("ListFile: After filter mode  = %{public}d", mode);
371 
372             fileInfoEntity.mode = mode;
373             fileInfoEntity.size = static_cast<int64_t>(statEntity.stat_.st_size);
374             fileInfoEntity.mtime = static_cast<int64_t>(statEntity.stat_.st_mtim.tv_sec);
375             fileInfoEntity.ctime = static_cast<int64_t>(statEntity.stat_.st_ctim.tv_sec);
376         }
377         fileInfoList.emplace_back(fileInfoEntity);
378     }
379     return fileInfoList;
380 }
381 
ListFile(napi_env env,napi_callback_info info)382 napi_value FileTrashNExporter::ListFile(napi_env env, napi_callback_info info)
383 {
384     if (!CheckCallingPermission(FILE_ACCESS_PERMISSION)) {
385         HILOG_ERROR("permission error");
386         NError(E_PERMISSION).ThrowErr(env);
387         return nullptr;
388     }
389 
390     NFuncArg funcArg(env, info);
391     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
392         HILOG_ERROR("Number of arguments unmatched");
393         NError(EINVAL).ThrowErr(env);
394         return nullptr;
395     }
396     vector<string> dirents;
397     unique_ptr<struct NameListArg, decltype(Deleter)*> pNameList = { new (nothrow) struct NameListArg, Deleter };
398     if (!pNameList) {
399         NError(ENOMEM).ThrowErr(env);
400         HILOG_ERROR("Failed to request heap memory.");
401         return nullptr;
402     }
403     int ret = RecursiveFunc(TRASH_PATH, dirents);
404     if (ret != ERRNO_NOERR) {
405         NError(ENOMEM).ThrowErr(env);
406         HILOG_ERROR("ListFile: Failed to recursive all Trash items path");
407         return nullptr;
408     }
409 
410     vector<string> filterDirents;
411     size_t slashSize = 1;
412     for (size_t j = 0; j < dirents.size(); j++) {
413         string dirent = dirents[j];
414         HILOG_DEBUG("ListFile: After RecursiveFunc dirent = %{public}s", dirent.c_str());
415 
416         string timeSlot = GetTimeSlotFromPath(dirent);
417         if (timeSlot.empty()) {
418             continue;
419         }
420         // Only filter previous dir is TRASH_SUB_DIR
421         size_t pos = dirent.find(TRASH_SUB_DIR + timeSlot + "/");
422         if (pos != string::npos) {
423             string trashSubDir = TRASH_SUB_DIR + timeSlot;
424             if (dirent.find("/", pos + trashSubDir.length() + slashSize) == string::npos) {
425                 filterDirents.emplace_back(dirent);
426             }
427         }
428     }
429     vector<FileInfo> fileInfoList = GenerateFileInfoEntities(filterDirents);
430     return CreateObjectArray(env, fileInfoList);
431 }
432 
RecoverFile(napi_env env,const string & filePath)433 static napi_value RecoverFile(napi_env env, const string &filePath)
434 {
435     string sourceFilePath = FindSourceFilePath(filePath);
436     HILOG_INFO("RecoverFile: sourceFilePath = %{public}s", sourceFilePath.c_str());
437     string newDestPath = sourceFilePath;
438     if (newDestPath.length() != 0 && Mkdirs(sourceFilePath, false, newDestPath)) {
439         MoveFile(filePath, newDestPath);
440     }
441 
442     // 文件已被移动,则如果前一层目录包含其他内容,则直接返回;
443     // 如果不包含,则需要一层层向父目录回退判断对应目录是否需要删除
444     size_t slashPos = filePath.find_last_of("/");
445     string parentPath = filePath.substr(0, slashPos);
446     int num = ScanDir(parentPath);
447     if (num == 0) {
448         auto err = RmDirent(GetToDeletePath(parentPath, env));
449         if (err) {
450             err.ThrowErr(env);
451             return nullptr;
452         }
453     }
454     return NVal::CreateUndefined(env).val_;
455 }
456 
RecoverFilePart(vector<string> filePathList,map<string,string> dirPath2UpdatedNameMap)457 static void RecoverFilePart(vector<string> filePathList, map<string, string> dirPath2UpdatedNameMap)
458 {
459     // 处理文件
460     for (size_t j = 0; j < filePathList.size(); j++) {
461         string filePath = filePathList[j];
462         HILOG_INFO("RecoverFilePart: filePath  = %{public}s", filePath.c_str());
463         string sourceFilePath = FindSourceFilePath(filePath);
464         HILOG_INFO("RecoverFilePart: sourceFilePath  = %{public}s", sourceFilePath.c_str());
465 
466         size_t lastSlashPos = sourceFilePath.find_last_of("/");
467         string fileName = sourceFilePath.substr(lastSlashPos + 1);
468         string sourceFilePathOnly = sourceFilePath.substr(0, lastSlashPos);
469         map<string, string>::iterator iter = dirPath2UpdatedNameMap.find(sourceFilePathOnly);
470         if (iter != dirPath2UpdatedNameMap.end()) {
471             sourceFilePath = iter->second + "/" + fileName;
472         }
473         MoveFile(filePath, sourceFilePath);
474     }
475 }
476 
FilterDirsNoContains(vector<string> dirPathList)477 static vector<string> FilterDirsNoContains(vector<string> dirPathList)
478 {
479     //先处理目录,仅保留不互相包含的目录(取子目录较深的)
480     vector<string> filterDirPathList;
481     for (size_t j = 0; j < dirPathList.size(); j++) {
482         string dirPath = dirPathList[j];
483         bool isIncluded = false;
484         for (size_t k = 0; k < filterDirPathList.size(); k++) {
485             string filterDirPath = filterDirPathList[k];
486             if (StartsWith(filterDirPath, dirPath)) {
487                 isIncluded = true;
488                 break;
489             }
490         }
491         if (!isIncluded) {
492             filterDirPathList.emplace_back(dirPath);
493         }
494     }
495     return filterDirPathList;
496 }
497 
MakeAndFindUpdateNameDir(vector<string> filterDirPathList)498 static map<string, string> MakeAndFindUpdateNameDir(vector<string> filterDirPathList)
499 {
500     map<string, string> dirPath2UpdatedNameMap;
501     for (size_t j = 0; j < filterDirPathList.size(); j++) {
502         string dirPath = filterDirPathList[j];
503         string sourceFilePath = FindSourceFilePath(dirPath);
504         HILOG_DEBUG("MakeAndFindUpdateNameDir: sourceFilePath  = %{public}s", sourceFilePath.c_str());
505         string newDestPath = sourceFilePath;
506         if (Mkdirs(sourceFilePath, true, newDestPath)) {
507             HILOG_DEBUG("MakeAndFindUpdateNameDir: newDestPath  = %{public}s", newDestPath.c_str());
508             if (newDestPath != sourceFilePath) {
509                 dirPath2UpdatedNameMap.insert(make_pair(sourceFilePath, newDestPath));
510             }
511         }
512     }
513     return dirPath2UpdatedNameMap;
514 }
515 
RecoverDir(napi_env env,const string & dirPath)516 static napi_value RecoverDir(napi_env env, const string &dirPath)
517 {
518     vector<string> dirents;
519     unique_ptr<struct NameListArg, decltype(Deleter)*> pNameList = { new (nothrow) struct NameListArg, Deleter };
520     if (!pNameList) {
521         HILOG_ERROR("RecoverDir: Failed to request heap memory.");
522         return nullptr;
523     }
524     int ret = RecursiveFunc(dirPath, dirents);
525     if (ret != ERRNO_NOERR) {
526         HILOG_ERROR("RecoverDir: Failed to Recursive Dir.");
527         return nullptr;
528     }
529     dirents.emplace_back(dirPath);
530 
531     // 区分目录和文件
532     vector<string> dirPathList;
533     vector<string> filePathList;
534     for (size_t j = 0; j < dirents.size(); j++) {
535         string dirent = dirents[j];
536         if (CheckDir(dirent)) {
537             dirPathList.emplace_back(dirent);
538         } else {
539             filePathList.emplace_back(dirent);
540         }
541     }
542     // 目录从长到短排序
543     sort(dirPathList.begin(), dirPathList.end(), [&](const string &a, const string &b) {
544         return a.length() > b.length();
545     });
546 
547     // 先处理目录,仅保留不互相包含的目录(取子目录较深的)
548     vector<string> filterDirPathList = FilterDirsNoContains(dirPathList);
549     if (filterDirPathList.size() == 0) {
550         HILOG_ERROR("RecoverDir: NO valid dirs found");
551         return nullptr;
552     }
553 
554     // 新建目录并获取因为存在同名目录修改过名称的目录
555     map<string, string> dirPath2UpdatedNameMap = MakeAndFindUpdateNameDir(filterDirPathList);
556 
557     // 处理文件部分
558     RecoverFilePart(filePathList, dirPath2UpdatedNameMap);
559 
560     // 删除目录
561     auto err = RmDirent(GetToDeletePath(dirPath, env));
562     if (err) {
563         err.ThrowErr(env);
564         return nullptr;
565     }
566 
567     return NVal::CreateUndefined(env).val_;
568 }
569 
Recover(napi_env env,napi_callback_info info)570 napi_value FileTrashNExporter::Recover(napi_env env, napi_callback_info info)
571 {
572     if (!CheckCallingPermission(FILE_ACCESS_PERMISSION)) {
573         HILOG_ERROR("permission error");
574         NError(E_PERMISSION).ThrowErr(env);
575         return nullptr;
576     }
577 
578     NFuncArg funcArg(env, info);
579     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
580         HILOG_ERROR("Number of arguments unmatched");
581         NError(EINVAL).ThrowErr(env);
582         return nullptr;
583     }
584     bool succ = false;
585     unique_ptr<char[]> uriPtr;
586     tie(succ, uriPtr, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
587     if (!succ) {
588         NError(EINVAL).ThrowErr(env);
589         return nullptr;
590     }
591     string uriStr = uriPtr.get();
592     HILOG_DEBUG("Recover: uriPtr.get()  = %{public}s", uriStr.c_str());
593 
594     // 获取沙箱目录地址
595     AppFileService::ModuleFileUri::FileUri fileUri(uriStr);
596     string path = fileUri.GetPath();
597     // 判断绝对路径
598     if (!GetRealPath(path)) {
599         NError(EINVAL).ThrowErr(env);
600         HILOG_ERROR("Recover: Invalid Path");
601         return nullptr;
602     }
603     HILOG_DEBUG("Recover: path  = %{public}s", path.c_str());
604 
605     // 判断是否是回收站路径
606     if (path.find(TRASH_PATH) == string::npos) {
607         NError(EINVAL).ThrowErr(env);
608         HILOG_ERROR("Recover: path  = %{public}s is not Trash path", path.c_str());
609         return nullptr;
610     }
611 
612     // 判断路径是否存在
613     auto [isExist, ret] = Access(path);
614     if (!isExist) {
615         NError(EINVAL).ThrowErr(env);
616         HILOG_ERROR("Recover: Path is not exist");
617         return nullptr;
618     }
619 
620     if (!CheckDir(path)) {
621         return RecoverFile(env, path);
622     }
623     return RecoverDir(env, path);
624 }
625 
CompletelyDelete(napi_env env,napi_callback_info info)626 napi_value FileTrashNExporter::CompletelyDelete(napi_env env, napi_callback_info info)
627 {
628     if (!CheckCallingPermission(FILE_ACCESS_PERMISSION)) {
629         HILOG_ERROR("permission error");
630         NError(E_PERMISSION).ThrowErr(env);
631         return nullptr;
632     }
633 
634     NFuncArg funcArg(env, info);
635     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
636         HILOG_ERROR("Number of arguments unmatched");
637         NError(EINVAL).ThrowErr(env);
638         return nullptr;
639     }
640     bool succ = false;
641     unique_ptr<char[]> uriPtr;
642     tie(succ, uriPtr, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
643     if (!succ) {
644         NError(EINVAL).ThrowErr(env);
645         HILOG_ERROR("Recover: Invalid arguments");
646         return nullptr;
647     }
648 
649     string uriStr = uriPtr.get();
650     HILOG_DEBUG("Recover: uriPtr.get()  = %{public}s", uriStr.c_str());
651 
652     // 获取沙箱目录地址
653     AppFileService::ModuleFileUri::FileUri fileUri(uriStr);
654     string path = fileUri.GetPath();
655     // 判断绝对路径
656     if (!GetRealPath(path)) {
657         NError(EINVAL).ThrowErr(env);
658         HILOG_ERROR("Recover: Invalid Path");
659         return nullptr;
660     }
661     HILOG_DEBUG("Recover: path  = %{public}s", path.c_str());
662 
663     // 判断是否是回收站路径
664     if (path.find(TRASH_PATH) == string::npos) {
665         NError(EINVAL).ThrowErr(env);
666         HILOG_ERROR("Recover: path  = %{public}s is not Trash path", path.c_str());
667         return nullptr;
668     }
669 
670     // 判断路径是否存在
671     auto [isExist, ret] = Access(path);
672     if (!isExist) {
673         NError(EINVAL).ThrowErr(env);
674         HILOG_ERROR("Recover: Path is not exist");
675         return nullptr;
676     }
677 
678     // 删除目录
679     auto err = RmDirent(GetToDeletePath(path, env));
680     if (err) {
681         err.ThrowErr(env);
682         return nullptr;
683     }
684     return NVal::CreateUndefined(env).val_;
685 }
686 
Export()687 bool FileTrashNExporter::Export()
688 {
689     return exports_.AddProp({
690         NVal::DeclareNapiFunction("listFile", ListFile),
691         NVal::DeclareNapiFunction("recover", Recover),
692         NVal::DeclareNapiFunction("completelyDelete", CompletelyDelete)
693     });
694 }
695 
GetClassName()696 string FileTrashNExporter::GetClassName()
697 {
698     return FileTrashNExporter::className_;
699 }
700 
FileTrashNExporter(napi_env env,napi_value exports)701 FileTrashNExporter::FileTrashNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
702 
~FileTrashNExporter()703 FileTrashNExporter::~FileTrashNExporter() {}
704 } // namespace Trash
705 } // namespace OHOS