• 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 #include "create_randomaccessfile.h"
16 
17 #include "class_file/file_entity.h"
18 #include "class_randomaccessfile/randomaccessfile_entity.h"
19 #include "class_randomaccessfile/randomaccessfile_n_exporter.h"
20 #include "common_func.h"
21 #include "file_utils.h"
22 
23 namespace OHOS {
24 namespace FileManagement {
25 namespace ModuleFileIO {
26 using namespace std;
27 using namespace OHOS::FileManagement::LibN;
28 
GetFileEntity(napi_env env,napi_value objFile)29 static FileEntity* GetFileEntity(napi_env env, napi_value objFile)
30 {
31     auto fileEntity = NClass::GetEntityOf<FileEntity>(env, objFile);
32     if (!fileEntity) {
33         HILOGE("Failed to get file entity");
34         return nullptr;
35     }
36     if (!fileEntity->fd_) {
37         HILOGE("The fd of entity is not exist");
38         return nullptr;
39     }
40     return fileEntity;
41 }
42 
ParseJsFile(napi_env env,napi_value pathOrFileFromJsArg)43 static tuple<bool, FileInfo, int> ParseJsFile(napi_env env, napi_value pathOrFileFromJsArg)
44 {
45     auto [isPath, path, ignore] = NVal(env, pathOrFileFromJsArg).ToUTF8StringPath();
46     if (isPath) {
47         OHOS::DistributedFS::FDGuard sfd;
48         auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(sfd, false);
49         if (fdg == nullptr) {
50             HILOGE("Failed to request heap memory.");
51             close(sfd);
52             return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
53         }
54         return { true, FileInfo { true, move(path), move(fdg) }, ERRNO_NOERR};
55     }
56     auto fileEntity = GetFileEntity(env, pathOrFileFromJsArg);
57     if (fileEntity) {
58         auto fd = fileEntity->fd_.get()->GetFD();
59         if (fd < 0) {
60             HILOGE("Invalid fd");
61             return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
62         }
63         auto dupFd = dup(fd);
64         if (dupFd < 0) {
65             HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd);
66             return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
67         }
68         auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(dupFd, false);
69         if (fdg == nullptr) {
70             HILOGE("Failed to request heap memory.");
71             close(dupFd);
72             return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
73         }
74         return { true, FileInfo { false, nullptr, move(fdg) }, ERRNO_NOERR};
75     }
76     HILOGE("The first argument requires filepath/file");
77     return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
78 }
79 
GetRafOptions(napi_env env,napi_value options)80 static tuple<bool, int64_t, int64_t> GetRafOptions(napi_env env, napi_value options)
81 {
82     NVal op = NVal(env, options);
83     int64_t opStart = INVALID_POS;
84     int64_t opEnd = INVALID_POS;
85     if (op.HasProp("start")) {
86         auto [succ, start] = op.GetProp("start").ToInt64();
87         if (!succ || start < 0) {
88             NError(EINVAL).ThrowErr(env, "Invalid option.start, positive integer is desired");
89             return {false, opStart, opEnd};
90         }
91         opStart = start;
92     }
93     if (op.HasProp("end")) {
94         auto [succ, end] = op.GetProp("end").ToInt64();
95         if (!succ || end < 0) {
96             NError(EINVAL).ThrowErr(env, "Invalid option.end, positive integer is desired");
97             return {false, opStart, opEnd};
98         }
99         opEnd = end;
100     }
101     return {true, opStart, opEnd};
102 }
103 
GetJsFlags(napi_env env,const NFuncArg & funcArg,FileInfo & fileInfo)104 static tuple<bool, unsigned int, int64_t, int64_t> GetJsFlags(napi_env env, const NFuncArg &funcArg, FileInfo &fileInfo)
105 {
106     unsigned int flags = O_RDONLY;
107     int64_t start = INVALID_POS;
108     int64_t end = INVALID_POS;
109     if (fileInfo.isPath && funcArg.GetArgc() >= NARG_CNT::TWO) {
110         auto [succ, mode] = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32(0);
111         if (!succ || mode < 0) {
112             HILOGE("Invalid flags");
113             NError(EINVAL).ThrowErr(env);
114             return {false, flags, start, end};
115         }
116         flags = static_cast<unsigned int>(mode);
117         (void)CommonFunc::ConvertJsFlags(flags);
118     }
119 
120     bool succOpt;
121     if (funcArg.GetArgc() == NARG_CNT::THREE && !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function)) {
122         tie(succOpt, start, end) = GetRafOptions(env, funcArg[NARG_POS::THIRD]);
123         if (!succOpt) {
124             HILOGE("invalid RandomAccessFile options");
125             NError(EINVAL).ThrowErr(env);
126             return {false, flags, start, end};
127         }
128     }
129 
130     return {true, flags, start, end};
131 }
132 
InstantiateRandomAccessFile(napi_env env,std::unique_ptr<DistributedFS::FDGuard> fdg,int64_t fp,int64_t start=INVALID_POS,int64_t end=INVALID_POS)133 static NVal InstantiateRandomAccessFile(napi_env env,
134                                         std::unique_ptr<DistributedFS::FDGuard> fdg,
135                                         int64_t fp,
136                                         int64_t start = INVALID_POS,
137                                         int64_t end = INVALID_POS)
138 {
139     napi_value objRAF = NClass::InstantiateClass(env, RandomAccessFileNExporter::className_, {});
140     if (!objRAF) {
141         HILOGE("Cannot instantiate randomaccessfile");
142         NError(EIO).ThrowErr(env);
143         return NVal();
144     }
145     auto rafEntity = NClass::GetEntityOf<RandomAccessFileEntity>(env, objRAF);
146     if (!rafEntity) {
147         HILOGE("Cannot instantiate randomaccessfile because of void entity");
148         NError(EIO).ThrowErr(env);
149         return NVal();
150     }
151     rafEntity->fd.swap(fdg);
152     rafEntity->filePointer = fp;
153     rafEntity->start = start;
154     rafEntity->end = end;
155     return {env, objRAF};
156 }
157 
Sync(napi_env env,napi_callback_info info)158 napi_value CreateRandomAccessFile::Sync(napi_env env, napi_callback_info info)
159 {
160     NFuncArg funcArg(env, info);
161     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
162         HILOGE("Number of arguments unmatched");
163         NError(EINVAL).ThrowErr(env);
164         return nullptr;
165     }
166     auto [succ, fileInfo, err] = ParseJsFile(env, funcArg[NARG_POS::FIRST]);
167     if (!succ) {
168         NError(err).ThrowErr(env);
169         return nullptr;
170     }
171     if (fileInfo.isPath) {
172         auto [succFlags, flags, ignoreStart, ignoreEnd] = GetJsFlags(env, funcArg, fileInfo);
173         if (!succFlags) {
174             return nullptr;
175         }
176         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
177             new uv_fs_t, CommonFunc::fs_req_cleanup };
178         if (!open_req) {
179             HILOGE("Failed to request heap memory.");
180             NError(ENOMEM).ThrowErr(env);
181             return nullptr;
182         }
183         int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), flags, S_IRUSR |
184             S_IWUSR | S_IRGRP | S_IWGRP, NULL);
185         if (ret < 0) {
186             NError(ret).ThrowErr(env);
187             return nullptr;
188         }
189 
190         fileInfo.fdg->SetFD(open_req.get()->result, false);
191     }
192     if (funcArg.GetArgc() == NARG_CNT::THREE) {
193         auto [succ, start, end] = GetRafOptions(env, funcArg[NARG_POS::THIRD]);
194         if (succ) {
195             return InstantiateRandomAccessFile(env, move(fileInfo.fdg), 0, start, end).val_;
196         }
197     }
198     return InstantiateRandomAccessFile(env, move(fileInfo.fdg), 0).val_;
199 }
200 
201 struct AsyncCreateRandomAccessFileArg {
202     int fd = 0;
203 };
204 
AsyncExec(shared_ptr<AsyncCreateRandomAccessFileArg> arg,shared_ptr<FileInfo> fileInfo,unsigned int flags)205 NError AsyncExec(shared_ptr<AsyncCreateRandomAccessFileArg> arg,
206     shared_ptr<FileInfo> fileInfo, unsigned int flags)
207 {
208     if (fileInfo->isPath) {
209         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
210             new uv_fs_t, CommonFunc::fs_req_cleanup };
211         int ret = uv_fs_open(nullptr, open_req.get(), fileInfo->path.get(), flags, S_IRUSR |
212             S_IWUSR | S_IRGRP | S_IWGRP, NULL);
213         if (ret < 0) {
214             return NError(ret);
215         }
216         fileInfo->fdg->SetFD(open_req.get()->result, false);
217     }
218     arg->fd = fileInfo->fdg->GetFD();
219     return NError(ERRNO_NOERR);
220 }
221 
Async(napi_env env,napi_callback_info info)222 napi_value CreateRandomAccessFile::Async(napi_env env, napi_callback_info info)
223 {
224     NFuncArg funcArg(env, info);
225     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
226         HILOGE("Number of arguments unmatched");
227         NError(EINVAL).ThrowErr(env);
228         return nullptr;
229     }
230     auto [succ, fileInfo, err] = ParseJsFile(env, funcArg[NARG_POS::FIRST]);
231     if (!succ) {
232         NError(err).ThrowErr(env);
233         return nullptr;
234     }
235     auto [succFlags, flags, start, end] = GetJsFlags(env, funcArg, fileInfo);
236     if (!succFlags) {
237         return nullptr;
238     }
239     auto arg = CreateSharedPtr<AsyncCreateRandomAccessFileArg>();
240     if (arg == nullptr) {
241         HILOGE("Failed to request heap memory.");
242         NError(ENOMEM).ThrowErr(env);
243         return nullptr;
244     }
245     auto movedFileInfo = CreateSharedPtr<FileInfo>(move(fileInfo));
246     if (movedFileInfo == nullptr) {
247         HILOGE("Failed to request heap memory.");
248         NError(ENOMEM).ThrowErr(env);
249         return nullptr;
250     }
251     auto cbExec = [arg, movedFileInfo, flags = flags]() -> NError {
252         return AsyncExec(arg, movedFileInfo, flags);
253     };
254 
255     auto cbCompl = [arg, movedFileInfo, start = start, end = end](napi_env env, NError err) -> NVal {
256         if (err) {
257             return { env, err.GetNapiErr(env) };
258         }
259         return InstantiateRandomAccessFile(env, move(movedFileInfo->fdg), 0, start, end);
260     };
261     NVal thisVar(env, funcArg.GetThisVar());
262     if (funcArg.GetArgc() == NARG_CNT::ONE ||
263         (funcArg.GetArgc() == NARG_CNT::TWO && NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number)) ||
264         (funcArg.GetArgc() == NARG_CNT::THREE && NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_object))) {
265         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_CREATERAT_NAME, cbExec, cbCompl).val_;
266     } else {
267         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD);
268         NVal cb(env, funcArg[cbIdx]);
269         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_CREATERAT_NAME, cbExec, cbCompl).val_;
270     }
271 }
272 } // namespace ModuleFileIO
273 } // namespace FileManagement
274 } // namespace OHOS