• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "create_randomaccessfile.h"
16 
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <memory>
21 #include <sstream>
22 #include <uv.h>
23 
24 #include "../../common/log.h"
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_class.h"
28 #include "../../common/napi/n_func_arg.h"
29 #include "../../common/uni_error.h"
30 #include "../common_func.h"
31 
32 #include "../class_randomaccessfile/randomaccessfile_entity.h"
33 #include "../class_randomaccessfile/randomaccessfile_n_exporter.h"
34 
35 namespace OHOS {
36 namespace DistributedFS {
37 namespace ModuleFileIO {
38 using namespace std;
39 
40 struct FileInfo {
41     bool isPath = false;
42     unique_ptr<char[]> path;
43     FDGuard fdg;
44 };
45 
CheckFilePath(napi_env env,string path)46 static bool CheckFilePath(napi_env env, string path)
47 {
48     if (access(path.c_str(), 0) == 0) {
49         struct stat fileStat;
50         int ret = stat(path.c_str(), &fileStat);
51         if (ret != 0) {
52             UniError(errno).ThrowErr(env, "Cannot stat filepath");
53             return false;
54         }
55         if ((fileStat.st_mode & S_IFMT) != S_IFREG) {
56             UniError(EINVAL).ThrowErr(env, "Invalid filepath");
57             return false;
58         }
59     }
60     return true;
61 }
62 
ParseJsFileAndFP(napi_env env,napi_value pathOrFdFromJsArg,napi_value FPFromJs)63 static tuple<bool, FileInfo, size_t> ParseJsFileAndFP(napi_env env, napi_value pathOrFdFromJsArg, napi_value FPFromJs)
64 {
65     auto [succ, fp] = NVal(env, FPFromJs).ToInt32();
66     if (succ) {
67         auto [isPath, path, ignore] = NVal(env, pathOrFdFromJsArg).ToUTF8String();
68         if (isPath) {
69             if (CheckFilePath(env, string(path.get()))) {
70                 return { true, FileInfo { true, move(path), {} }, fp };
71             }
72             return { false, FileInfo { false, {}, {} }, -1 };
73         }
74         auto [isFd, fd] = NVal(env, pathOrFdFromJsArg).ToInt32();
75         if (isFd) {
76             if (fd < 0) {
77                 UniError(EINVAL).ThrowErr(env, "Invalid fd");
78                 return { false, FileInfo { false, {}, {} }, -1 };
79             }
80             return { true, FileInfo { false, {}, { fd, false } }, fp };
81         }
82         UniError(EINVAL).ThrowErr(env, "The first argument requires filepath/fd");
83     }
84     UniError(EINVAL).ThrowErr(env, "Invalid fp");
85     return { false, FileInfo { false, {}, {} }, -1 };
86 };
87 
GetJsFlags(napi_env env,const NFuncArg & funcArg,FileInfo & fileInfo)88 static tuple<bool, int> GetJsFlags(napi_env env, const NFuncArg &funcArg, FileInfo &fileInfo)
89 {
90     int flags = O_RDONLY;
91     bool succ = false;
92     if (fileInfo.isPath) {
93         if (funcArg.GetArgc() >= NARG_CNT::THREE && !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function)) {
94             tie(succ, flags) = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32();
95             if (!succ) {
96                 UniError(EINVAL).ThrowErr(env, "Invalid flags");
97                 return { false, flags };
98             }
99             (void)CommonFunc::ConvertJsFlags(flags);
100         }
101     }
102     return { true, flags };
103 }
104 
InstantiateRandomAccessFile(napi_env env,int fd,size_t fp)105 static NVal InstantiateRandomAccessFile(napi_env env, int fd, size_t fp)
106 {
107     napi_value objRAF = NClass::InstantiateClass(env, RandomAccessFileNExporter::className_, {});
108     if (!objRAF) {
109         UniError(EIO).ThrowErr(env, "Cannot instantiate randomaccessfile");
110         return NVal();
111     }
112 
113     auto rafEntity = NClass::GetEntityOf<RandomAccessFileEntity>(env, objRAF);
114     if (!rafEntity) {
115         UniError(EIO).ThrowErr(env, "Cannot instantiate randomaccessfile because of void entity");
116         return NVal();
117     }
118     auto fdg = make_unique<FDGuard>(fd);
119     rafEntity->fd_.swap(fdg);
120     rafEntity->fpointer = fp;
121     return { env, objRAF };
122 }
123 
Sync(napi_env env,napi_callback_info info)124 napi_value CreateRandomAccessFile::Sync(napi_env env, napi_callback_info info)
125 {
126     NFuncArg funcArg(env, info);
127     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
128         UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
129         return nullptr;
130     }
131     auto [succ, fileInfo, fp] = ParseJsFileAndFP(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
132     if (!succ) {
133         return nullptr;
134     }
135 
136     if (fileInfo.isPath) {
137         auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo);
138         if (!succFlags) {
139             return nullptr;
140         }
141         uv_loop_s *loop = nullptr;
142         napi_get_uv_event_loop(env, &loop);
143         uv_fs_t open_req;
144         int ret = uv_fs_open(loop, &open_req, fileInfo.path.get(), flags, S_IRUSR |
145             S_IWUSR | S_IRGRP | S_IWGRP, NULL);
146         if (ret < 0) {
147             UniError(errno).ThrowErr(env);
148             return nullptr;
149         }
150         fileInfo.fdg.SetFD(open_req.result, false);
151         uv_fs_req_cleanup(&open_req);
152     }
153     return InstantiateRandomAccessFile(env, fileInfo.fdg.GetFD(), fp).val_;
154 }
155 
156 struct AsyncCreateRandomAccessFileArg {
157     int fd;
158     size_t fp;
159 };
160 
Async(napi_env env,napi_callback_info info)161 napi_value CreateRandomAccessFile::Async(napi_env env, napi_callback_info info)
162 {
163     NFuncArg funcArg(env, info);
164     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) {
165         UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
166         return nullptr;
167     }
168     auto [succ, fileInfo, fp] = ParseJsFileAndFP(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
169     if (!succ) {
170         return nullptr;
171     }
172     auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo);
173     if (!succFlags) {
174         return nullptr;
175     }
176     auto arg = make_shared<AsyncCreateRandomAccessFileArg>();
177     auto cbExec = [arg, fileInfo = make_shared<FileInfo>(move(fileInfo)), fp = fp, flags =
178         flags](napi_env env) -> UniError {
179         if (fileInfo->isPath) {
180             uv_loop_s *loop = nullptr;
181             napi_get_uv_event_loop(env, &loop);
182             uv_fs_t open_req;
183             int ret = uv_fs_open(loop, &open_req, fileInfo->path.get(), flags, S_IRUSR |
184                 S_IWUSR | S_IRGRP | S_IWGRP, NULL);
185             if (ret < 0) {
186                 return UniError(errno);
187             }
188             fileInfo->fdg.SetFD(open_req.result, false);
189             uv_fs_req_cleanup(&open_req);
190         }
191         arg->fd = fileInfo->fdg.GetFD();
192         arg->fp = fp;
193         return UniError(ERRNO_NOERR);
194     };
195     auto cbCompl = [arg](napi_env env, UniError err) -> NVal {
196         if (err) {
197             return { env, err.GetNapiErr(env) };
198         }
199         return InstantiateRandomAccessFile(env, arg->fd, arg->fp);
200     };
201     NVal thisVar(env, funcArg.GetThisVar());
202     if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE &&
203         NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number))) {
204         return NAsyncWorkPromise(env, thisVar).Schedule(createRAFProcedureName, cbExec, cbCompl).val_;
205     } else {
206         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::FOUR) ? NARG_POS::FOURTH : NARG_POS::THIRD);
207         NVal cb(env, funcArg[cbIdx]);
208         return NAsyncWorkCallback(env, thisVar, cb).Schedule(createRAFProcedureName, cbExec, cbCompl).val_;
209     }
210 }
211 } // namespace ModuleFileIO
212 } // namespace DistributedFS
213 } // namespace OHOS