1 /*
2  * Copyright (c) 2022 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 "rmdirent.h"
17 
18 #include <cstring>
19 #include <dirent.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <tuple>
23 #include <unistd.h>
24 
25 #include "../../common/napi/n_async/n_async_work_callback.h"
26 #include "../../common/napi/n_async/n_async_work_promise.h"
27 #include "../../common/napi/n_func_arg.h"
28 
29 namespace OHOS {
30 namespace DistributedFS {
31 namespace ModuleFileIO {
32 using namespace std;
33 
ParseJsPath(napi_env env,napi_value pathFromJs)34 static tuple<bool, unique_ptr<char[]>> ParseJsPath(napi_env env, napi_value pathFromJs)
35 {
36     auto [succ, path, ignore] = NVal(env, pathFromJs).ToUTF8StringPath();
37     return {succ, move(path)};
38 }
39 
rmdirent(napi_env env,string path)40 static UniError rmdirent(napi_env env, string path)
41 {
42     if (rmdir(path.c_str()) == 0) {
43         return UniError(ERRNO_NOERR);
44     }
45     auto dir = opendir(path.c_str());
46     if (!dir) {
47         return UniError(errno);
48     }
49     struct dirent* entry = readdir(dir);
50     while (entry) {
51         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
52             entry = readdir(dir);
53             continue;
54         }
55         struct stat fileInformation;
56         string filePath = path + '/';
57         filePath.insert(filePath.length(), entry->d_name);
58         if (stat(filePath.c_str(), &fileInformation) != 0) {
59             closedir(dir);
60             return UniError(errno);
61         }
62         if ((fileInformation.st_mode & S_IFMT) == S_IFDIR) {
63             auto err = rmdirent(env, filePath);
64             if (err) {
65                 closedir(dir);
66                 return err;
67             }
68         } else {
69             if (unlink(filePath.c_str()) != 0) {
70                 closedir(dir);
71                 return UniError(errno);
72             }
73         }
74         entry = readdir(dir);
75     }
76     closedir(dir);
77     if (rmdir(path.c_str()) != 0) {
78         return UniError(errno);
79     }
80     return UniError(ERRNO_NOERR);
81 }
82 
Sync(napi_env env,napi_callback_info info)83 napi_value Rmdirent::Sync(napi_env env, napi_callback_info info)
84 {
85     NFuncArg funcArg(env, info);
86 
87     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
88         UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
89         return nullptr;
90     }
91 
92     auto [succ, path] = ParseJsPath(env, funcArg[NARG_POS::FIRST]);
93     if (!succ) {
94         UniError(EINVAL).ThrowErr(env, "Invalid path");
95         return nullptr;
96     }
97 
98     auto err = rmdirent(env, string(path.get()));
99     if (err) {
100         err.ThrowErr(env);
101         return nullptr;
102     }
103     return NVal::CreateUndefined(env).val_;
104 }
105 
Async(napi_env env,napi_callback_info info)106 napi_value Rmdirent::Async(napi_env env, napi_callback_info info)
107 {
108     NFuncArg funcArg(env, info);
109     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
110         UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
111         return nullptr;
112     }
113 
114     auto [succ, path] = ParseJsPath(env, funcArg[NARG_POS::FIRST]);
115     if (!succ) {
116         UniError(EINVAL).ThrowErr(env, "Invalid path");
117         return nullptr;
118     }
119 
120     auto cbExec = [path = string(path.get())](napi_env env) -> UniError {
121         return rmdirent(env, path);
122     };
123     auto cbCompl = [](napi_env env, UniError err) -> NVal {
124         if (err) {
125             return { env, err.GetNapiErr(env) };
126         } else {
127             return NVal::CreateUndefined(env);
128         }
129     };
130 
131     NVal thisVar(env, funcArg.GetThisVar());
132     size_t argc = funcArg.GetArgc();
133     if (argc == NARG_CNT::ONE) {
134         return NAsyncWorkPromise(env, thisVar).Schedule(rmdirProcedureName, cbExec, cbCompl).val_;
135     } else {
136         NVal cb(env, funcArg[NARG_POS::SECOND]);
137         return NAsyncWorkCallback(env, thisVar, cb).Schedule(rmdirProcedureName, cbExec, cbCompl).val_;
138     }
139 }
140 } // namespace ModuleFileIO
141 } // namespace DistributedFS
142 } // namespace OHOS