• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_manager_napi.h"
17 
18 #include <cstring>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 
23 #include "file_manager_napi_def.h"
24 #include "file_manager_proxy.h"
25 #include "file_manager_service_def.h"
26 #include "file_manager_service_errno.h"
27 #include "ifms_client.h"
28 #include "log.h"
29 namespace OHOS {
30 namespace FileManagerService {
31 using namespace std;
32 using namespace DistributedFS;
33 struct AsyncFileInfoArg {
34     NRef ref_;
35     vector<shared_ptr<FileInfo>> fileRes_;
AsyncFileInfoArgOHOS::FileManagerService::AsyncFileInfoArg36     explicit AsyncFileInfoArg(NVal ref) : ref_(ref), fileRes_() {};
37     ~AsyncFileInfoArg() = default;
38 };
39 
40 struct AsyncUriArg {
41     NRef ref_;
42     string uri_;
AsyncUriArgOHOS::FileManagerService::AsyncUriArg43     explicit AsyncUriArg(NVal ref) : ref_(ref), uri_() {};
44     ~AsyncUriArg() = default;
45 };
46 
GetFmsClient()47 tuple<bool, IFmsClient*> FileManagerNapi::GetFmsClient()
48 {
49     if (fmsClient_ == nullptr) {
50         fmsClient_ = IFmsClient::GetFmsInstance();
51     }
52     if (fmsClient_ == nullptr) {
53         ERR_LOG("fms get instance fails");
54         return make_tuple(false, nullptr);
55     } else {
56         return make_tuple(true, fmsClient_);
57     }
58 }
59 
DealWithErrno(int err)60 UniError DealWithErrno(int err)
61 {
62     unordered_map<int, int> errMap = {
63         {FAIL, ESRCH},
64         {E_CREATE_FAIL, EPERM},
65         {E_NOEXIST, ENOENT},
66         {E_EMPTYFOLDER, ENOTDIR},
67         {SUCCESS, ERRNO_NOERR},
68     };
69     if (errMap.count(err) == 0) {
70         ERR_LOG("unhandler err number %{public}d", err);
71         return UniError(EACCES);
72     } else {
73         return UniError(errMap[err]);
74     }
75 }
76 
GetDevInfoArg(const NVal & prop,DevInfo & dev)77 bool GetDevInfoArg(const NVal &prop, DevInfo &dev)
78 {
79     if (prop.HasProp("name")) {
80         bool ret = false;
81         unique_ptr<char[]> name;
82         tie(ret, name, ignore) = prop.GetProp("name").ToUTF8String();
83         if (!ret) {
84             return false;
85         }
86         dev.SetName(std::string(name.get()));
87     }
88     return true;
89 }
90 
GetCreateFileArgs(napi_env env,NFuncArg & funcArg)91 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>, CmdOptions> GetCreateFileArgs(napi_env env, NFuncArg &funcArg)
92 {
93     bool succ = false;
94     unique_ptr<char[]> path;
95     unique_ptr<char[]> fileName;
96     CmdOptions option("local", "", 0, MAX_NUM, false);
97     tie(succ, path, ignore) = NVal(env, funcArg[CreateFileArgs::CF_PATH]).ToUTF8String();
98     if (!succ) {
99         return {false, nullptr, nullptr, option};
100     }
101     tie(succ, fileName, ignore) = NVal(env, funcArg[CreateFileArgs::CF_FILENAME]).ToUTF8String();
102     if (!succ) {
103         return {false, nullptr, nullptr, option};
104     }
105 
106     if (funcArg.GetArgc() < CreateFileArgs::CF_OPTION) {
107         return {false, nullptr, nullptr, option};
108     }
109 
110     NVal op(env, NVal(env, funcArg[CreateFileArgs::CF_OPTION]).val_);
111     if (op.TypeIs(napi_function)) {
112         return {true, move(path), move(fileName), option};
113     }
114 
115     option.SetHasOpt(true);
116     if (!op.HasProp("dev")) {
117         return {true, move(path), move(fileName), option};
118     }
119 
120     NVal prop(op.GetProp("dev"));
121     DevInfo dev("local", "");
122     if (!GetDevInfoArg(prop, dev)) {
123         ERR_LOG("CreateFile func get dev para fails");
124         option.SetDevInfo(dev);
125         return {false, nullptr, nullptr, option};
126     }
127 
128     option.SetDevInfo(dev);
129     return {true, move(path), move(fileName), option};
130 }
131 
CreateFile(napi_env env,napi_callback_info info)132 napi_value FileManagerNapi::CreateFile(napi_env env, napi_callback_info info)
133 {
134     NFuncArg funcArg(env, info);
135     if (!funcArg.InitArgs(CREATE_FILE_PARA_MIN, CREATE_FILE_PARA_MAX)) {
136         UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
137         return nullptr;
138     }
139     bool succ = false;
140     unique_ptr<char[]> path;
141     unique_ptr<char[]> fileName;
142     CmdOptions option;
143     tie(succ, path, fileName, option) = GetCreateFileArgs(env, funcArg);
144     if (!succ) {
145         UniError(EINVAL).ThrowErr(env, "CreateFile func get args fails");
146         return nullptr;
147     }
148     auto arg = make_shared<AsyncUriArg>(NVal(env, funcArg.GetThisVar()));
149     auto cbExec = [arg, path = string(path.get()), fileName = string(fileName.get()), option = option]
150         (napi_env env) -> UniError {
151         IFmsClient* client = nullptr;
152         bool succ = false;
153         tie(succ, client) = GetFmsClient();
154         if (!succ) {
155             return UniError(ESRCH);
156         }
157         string uri = "";
158         int err = client->CreateFile(path, fileName, option, arg->uri_);
159         return DealWithErrno(err);
160     };
161     auto cbComplete = [arg](napi_env env, UniError err) -> NVal {
162         if (err) {
163             return { env, err.GetNapiErr(env) };
164         } else {
165             return NVal::CreateUTF8String(env, arg->uri_);
166         }
167     };
168     string procedureName = "CreateFile";
169     size_t argc = funcArg.GetArgc();
170     NVal thisVar(env, funcArg.GetThisVar());
171     if (argc == CREATE_FILE_PARA_MIN || (argc != CREATE_FILE_PARA_MAX && option.GetHasOpt())) {
172         return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbComplete).val_;
173     } else {
174         int cbIdx = (!option.GetHasOpt() ?
175             CreateFileArgs::CF_CALLBACK_WITHOUT_OP : CreateFileArgs::CF_CALLBACK_WITH_OP);
176         NVal cb(env, funcArg[cbIdx]);
177         return NAsyncWorkCallback(env, thisVar, cb).Schedule(procedureName, cbExec, cbComplete).val_;
178     }
179 }
180 
CreateFileArray(napi_env env,shared_ptr<AsyncFileInfoArg> arg)181 static bool CreateFileArray(napi_env env, shared_ptr<AsyncFileInfoArg> arg)
182 {
183     for (size_t i = 0; i < arg->fileRes_.size(); i++) {
184         NVal obj = NVal::CreateObject(env);
185         shared_ptr<FileInfo> res = arg->fileRes_[i];
186         if (res == nullptr) {
187             ERR_LOG("inner error, lack of memory, file count %{public}d", arg->fileRes_.size());
188             return false;
189         }
190         obj.AddProp("name", NVal::CreateUTF8String(env, res->GetName()).val_);
191         obj.AddProp("path", NVal::CreateUTF8String(env, res->GetPath()).val_);
192         obj.AddProp("type", NVal::CreateUTF8String(env, res->GetType()).val_);
193         obj.AddProp("size", NVal::CreateInt64(env, res->GetSize()).val_);
194         obj.AddProp("added_time", NVal::CreateInt64(env, res->GetAddedTime()).val_);
195         obj.AddProp("modified_time", NVal::CreateInt64(env, res->GetModifiedTime()).val_);
196         napi_set_property(env, arg->ref_.Deref(env).val_, NVal::CreateInt32(env, i).val_, obj.val_);
197     }
198     return true;
199 }
200 
GetRootArgs(napi_env env,NFuncArg & funcArg,CmdOptions & option)201 bool GetRootArgs(napi_env env, NFuncArg &funcArg, CmdOptions &option)
202 {
203     NVal op(env, NVal(env, funcArg[GetRootArgs::GR_OPTION]).val_);
204     if (op.TypeIs(napi_function)) {
205         return true;
206     }
207 
208     option.SetHasOpt(true);
209     if (!op.HasProp("dev")) {
210         return true;
211     }
212 
213     NVal prop(op.GetProp("dev"));
214     DevInfo dev("local", "");
215     if (!GetDevInfoArg(prop, dev)) {
216         option.SetDevInfo(dev);
217         return false;
218     }
219 
220     option.SetDevInfo(dev);
221     return true;
222 }
223 
GetRoot(napi_env env,napi_callback_info info)224 napi_value FileManagerNapi::GetRoot(napi_env env, napi_callback_info info)
225 {
226     NFuncArg funcArg(env, info);
227     if (!funcArg.InitArgs(GET_ROOT_PARA_MIN, GET_ROOT_PARA_MAX)) {
228         UniError(EINVAL).ThrowErr(env, "Number of argments unmatched");
229         return nullptr;
230     }
231 
232     CmdOptions option("local", "", 0, MAX_NUM, false);
233     if (funcArg.GetArgc() != 0) {
234         if (!GetRootArgs(env, funcArg, option)) {
235             UniError(EINVAL).ThrowErr(env, "GetRoot func get dev para fails");
236             return nullptr;
237         }
238     }
239 
240     napi_value fileArr;
241     napi_create_array(env, &fileArr);
242     auto arg = make_shared<AsyncFileInfoArg>(NVal(env, fileArr));
243     auto cbExec = [option = option, arg] (napi_env env) -> UniError {
244         IFmsClient* client = nullptr;
245         bool succ = false;
246         tie(succ, client) = GetFmsClient();
247         if (!succ) {
248             return UniError(ESRCH);
249         }
250         int err = client->GetRoot(option, arg->fileRes_);
251         return DealWithErrno(err);
252     };
253     auto cbComplete = [arg](napi_env env, UniError err) -> NVal {
254         if (!err && !CreateFileArray(env, arg)) {
255             err = UniError(ENOMEM);
256         }
257         if (err) {
258             return { env, err.GetNapiErr(env) };
259         } else {
260             return NVal(env, arg->ref_.Deref(env).val_);
261         }
262     };
263     string procedureName = "GetRoot";
264     size_t argc = funcArg.GetArgc();
265     NVal thisVar(env, funcArg.GetThisVar());
266     if (argc == GET_ROOT_PARA_MIN || (argc != GET_ROOT_PARA_MAX && option.GetHasOpt())) {
267         return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbComplete).val_;
268     } else {
269         int cbIdx = (!option.GetHasOpt() ? GetRootArgs::GR_CALLBACK_WITHOUT_OP : GetRootArgs::GR_CALLBACK_WITH_OP);
270         NVal cb(env, funcArg[cbIdx]);
271         return NAsyncWorkCallback(env, thisVar, cb).Schedule(procedureName, cbExec, cbComplete).val_;
272     }
273 }
274 
GetListFileOption(const NVal & argv,CmdOptions & option)275 bool GetListFileOption(const NVal &argv, CmdOptions &option)
276 {
277     bool ret = false;
278     if (argv.HasProp("dev")) {
279         NVal prop(argv.GetProp("dev"));
280         DevInfo dev("local", "");
281         if (!GetDevInfoArg(prop, dev)) {
282             option.SetDevInfo(dev);
283             return false;
284         }
285         option.SetDevInfo(dev);
286     }
287     if (argv.HasProp("offset")) {
288         int64_t offset;
289         tie(ret, offset) = argv.GetProp("offset").ToInt64();
290         if (!ret) {
291             ERR_LOG("ListFileArgs LF_OPTION offset para fails");
292             return false;
293         }
294         option.SetOffset(offset);
295     }
296     if (argv.HasProp("count")) {
297         int64_t count;
298         tie(ret, count) = argv.GetProp("count").ToInt64();
299         if (!ret) {
300             ERR_LOG("ListFileArgs LF_OPTION count para fails");
301             return false;
302         }
303         option.setCount(count);
304     }
305     return true;
306 }
307 
GetListFileArg(napi_env env,NFuncArg & funcArg)308 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>, CmdOptions> GetListFileArg(
309     napi_env env, NFuncArg &funcArg)
310 {
311     bool succ = false;
312     unique_ptr<char[]> path;
313     unique_ptr<char[]> type;
314     CmdOptions option("local", "", 0, MAX_NUM, false);
315     tie(succ, path, ignore) = NVal(env, funcArg[ListFileArgs::LF_PATH]).ToUTF8String();
316     if (!succ) {
317         ERR_LOG("ListFileArgs LF_PATH para fails");
318         return {false, nullptr, nullptr, option};
319     }
320     tie(succ, type, ignore) = NVal(env, funcArg[ListFileArgs::LF_TYPE]).ToUTF8String();
321     if (!succ) {
322         ERR_LOG("ListFileArgs LF_TYPE para fails");
323         return {false, nullptr, nullptr, option};
324     }
325 
326     NVal op(env, NVal(env, funcArg[ListFileArgs::LF_OPTION]).val_);
327     if (op.TypeIs(napi_function)) {
328         return {true, move(type), move(path), option};
329     }
330     option.SetHasOpt(true);
331     if (!GetListFileOption(op, option)) {
332         return {false, nullptr, nullptr, option};
333     }
334     return {true, move(type), move(path), option};
335 }
336 
ListFile(napi_env env,napi_callback_info info)337 napi_value FileManagerNapi::ListFile(napi_env env, napi_callback_info info)
338 {
339     NFuncArg funcArg(env, info);
340     if (!funcArg.InitArgs(LIST_FILE_PARA_MIN, LIST_FILE_PARA_MAX)) {
341         UniError(EINVAL).ThrowErr(env, "Number of argments unmatched");
342         return nullptr;
343     }
344     bool succ = false;
345     unique_ptr<char[]> type;
346     unique_ptr<char[]> path;
347     CmdOptions option;
348     tie(succ, type, path, option) = GetListFileArg(env, funcArg);
349     if (!succ) {
350         UniError(EINVAL).ThrowErr(env, "Get argments fails");
351         return nullptr;
352     }
353     napi_value fileArr;
354     napi_create_array(env, &fileArr);
355     auto arg = make_shared<AsyncFileInfoArg>(NVal(env, fileArr));
356     auto cbExec = [type = string(type.get()), path = string(path.get()), option, arg](napi_env env) -> UniError {
357         IFmsClient* client = nullptr;
358         bool succ = false;
359         tie(succ, client) = GetFmsClient();
360         if (!succ) {
361             return UniError(ESRCH);
362         }
363         int err = client->ListFile(type, path, option, arg->fileRes_);
364         return DealWithErrno(err);
365     };
366 
367     auto cbComplete = [arg](napi_env env, UniError err) -> NVal {
368         if (!err && !CreateFileArray(env, arg)) {
369             err = UniError(ENOMEM);
370         }
371         if (err) {
372             return { env, err.GetNapiErr(env) };
373         } else {
374             return NVal(env, arg->ref_.Deref(env).val_);
375         }
376     };
377     string procedureName = "ListFile";
378     size_t argc = funcArg.GetArgc();
379     NVal thisVar(env, funcArg.GetThisVar());
380     if (argc == LIST_FILE_PARA_MIN || (argc != LIST_FILE_PARA_MAX && option.GetHasOpt())) {
381         return NAsyncWorkPromise(env, thisVar).Schedule(procedureName, cbExec, cbComplete).val_;
382     } else {
383         int cbIdx = ((!option.GetHasOpt()) ? ListFileArgs::LF_CALLBACK_WITHOUT_OP : ListFileArgs::LF_CALLBACK_WITH_OP);
384         NVal cb(env, funcArg[cbIdx]);
385         return NAsyncWorkCallback(env, thisVar, cb).Schedule(procedureName, cbExec, cbComplete).val_;
386     }
387 }
388 
Mkdir(napi_env env,napi_callback_info info)389 napi_value FileManagerNapi::Mkdir(napi_env env, napi_callback_info info)
390 {
391     return NVal::CreateUndefined(env).val_;
392 }
393 
Export()394 bool FileManagerNapi::Export()
395 {
396     return exports_.AddProp( {
397         NVal::DeclareNapiFunction("listFile", ListFile),
398         NVal::DeclareNapiFunction("createFile", CreateFile),
399         NVal::DeclareNapiFunction("getRoot", GetRoot),
400     });
401 }
402 
GetClassName()403 string FileManagerNapi::GetClassName()
404 {
405     return FileManagerNapi::className_;
406 }
407 
FileManagerNapi(napi_env env,napi_value exports)408 FileManagerNapi::FileManagerNapi(napi_env env, napi_value exports) : NExporter(env, exports) {}
409 
~FileManagerNapi()410 FileManagerNapi::~FileManagerNapi() {}
411 } // namespace FileManagerService
412 } // namespace OHOS
413