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 "read_dir.h"
17 
18 #include <dirent.h>
19 #include <memory>
20 #include <string>
21 #include <tuple>
22 
23 #include "../../common/napi/n_async/n_async_work_callback.h"
24 #include "../../common/napi/n_async/n_async_work_promise.h"
25 #include "../../common/napi/n_class.h"
26 #include "../../common/napi/n_func_arg.h"
27 #include "../../common/napi/n_val.h"
28 #include "../../common/uni_error.h"
29 
30 namespace OHOS {
31 namespace DistributedFS {
32 namespace ModuleFileIO {
33 using namespace std;
34 
ParseJsPath(napi_env env,napi_value pathFromJs)35 static tuple<bool, unique_ptr<char[]>> ParseJsPath(napi_env env, napi_value pathFromJs)
36 {
37     auto [succ, path, ignore] = NVal(env, pathFromJs).ToUTF8StringPath();
38     return {succ, move(path)};
39 }
40 
VerifyFilePath(char * path)41 static bool VerifyFilePath(char* path)
42 {
43     return strcmp(path, ".") != 0 && strcmp(path, "..") != 0;
44 }
45 
Sync(napi_env env,napi_callback_info info)46 napi_value ReadDir::Sync(napi_env env, napi_callback_info info)
47 {
48     NFuncArg funcArg(env, info);
49     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
50         return nullptr;
51     }
52     auto [succ, path] = ParseJsPath(env, funcArg[NARG_POS::FIRST]);
53     if (!succ) {
54         UniError(EINVAL).ThrowErr(env, "Invalid path");
55         return nullptr;
56     }
57     unique_ptr<DIR, function<void(DIR *)>> dir = { opendir(path.get()), closedir };
58     if (!dir) {
59         UniError(errno).ThrowErr(env);
60         return nullptr;
61     }
62     vector<string> dirFiles;
63     struct dirent* entry = readdir(dir.get());
64     while (entry) {
65         if (VerifyFilePath(entry->d_name)) {
66             dirFiles.push_back(entry->d_name);
67         }
68         entry = readdir(dir.get());
69     }
70     return NVal::CreateArrayString(env, dirFiles).val_;
71 }
72 
73 struct ReadDirArgs {
74     vector<string> dirFiles;
ReadDirArgsOHOS::DistributedFS::ModuleFileIO::ReadDirArgs75     explicit ReadDirArgs()
76     {
77         dirFiles = vector<string>();
78     }
79     ~ReadDirArgs() = default;
80 };
81 
Async(napi_env env,napi_callback_info info)82 napi_value ReadDir::Async(napi_env env, napi_callback_info info)
83 {
84     NFuncArg funcArg(env, info);
85     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
86         UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
87         return nullptr;
88     }
89     string path;
90     auto [succ, tmp] = ParseJsPath(env, funcArg[NARG_POS::FIRST]);
91     if (!succ) {
92         UniError(EINVAL).ThrowErr(env, "Invalid path");
93         return nullptr;
94     }
95     path = tmp.get();
96     auto arg = make_shared<ReadDirArgs>();
97     auto cbExec = [arg, path](napi_env env) -> UniError {
98         unique_ptr<DIR, function<void(DIR *)>> dir = { opendir(path.c_str()), closedir };
99         if (!dir) {
100             return UniError(errno);
101         }
102         struct dirent* entry = readdir(dir.get());
103         vector<string> dirnames;
104         while (entry) {
105             if (VerifyFilePath(entry->d_name)) {
106                 dirnames.push_back(entry->d_name);
107             }
108             entry = readdir(dir.get());
109         }
110         arg->dirFiles = dirnames;
111         return UniError(ERRNO_NOERR);
112     };
113     auto cbCompl = [arg](napi_env env, UniError err) -> NVal {
114         if (err) {
115             return { env, err.GetNapiErr(env) };
116         } else {
117             return NVal::CreateArrayString(env, arg->dirFiles);
118         }
119     };
120 
121     NVal thisVar(env, funcArg.GetThisVar());
122     if (funcArg.GetArgc() == NARG_CNT::ONE) {
123         return NAsyncWorkPromise(env, thisVar).Schedule(readdirProcedureName, cbExec, cbCompl).val_;
124     } else {
125         NVal cb(env, funcArg[NARG_POS::SECOND]);
126         return NAsyncWorkCallback(env, thisVar, cb).Schedule(readdirProcedureName, cbExec, cbCompl).val_;
127     }
128 }
129 } // namespace ModuleFileIO
130 } // namespace DistributedFS
131 } // namespace OHOS