• 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).ToUTF8String();
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             return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
52         }
53         return { true, FileInfo { true, move(path), move(fdg) }, ERRNO_NOERR};
54     }
55     auto fileEntity = GetFileEntity(env, pathOrFileFromJsArg);
56     if (fileEntity) {
57         auto fd = fileEntity->fd_.get()->GetFD();
58         if (fd < 0) {
59             HILOGE("Invalid fd");
60             return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
61         }
62         auto dupFd = dup(fd);
63         if (dupFd < 0) {
64             HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd);
65             return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
66         }
67         auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(dupFd, false);
68         if (fdg == nullptr) {
69             HILOGE("Failed to request heap memory.");
70             return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
71         }
72         return { true, FileInfo { false, nullptr, move(fdg) }, ERRNO_NOERR};
73     }
74     HILOGE("The first argument requires filepath/file");
75     return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
76 }
77 
GetJsFlags(napi_env env,const NFuncArg & funcArg,FileInfo & fileInfo)78 static tuple<bool, unsigned int> GetJsFlags(napi_env env, const NFuncArg &funcArg, FileInfo &fileInfo)
79 {
80     unsigned int flags = O_RDONLY;
81     if (fileInfo.isPath) {
82         if (funcArg.GetArgc() >= NARG_CNT::TWO) {
83             auto [succ, mode] = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32(0);
84             if (!succ || mode < 0) {
85                 HILOGE("Invalid flags");
86                 NError(EINVAL).ThrowErr(env);
87                 return { false, flags };
88             }
89             flags = static_cast<unsigned int>(mode);
90             (void)CommonFunc::ConvertJsFlags(flags);
91         }
92     }
93     return { true, flags };
94 }
95 
InstantiateRandomAccessFile(napi_env env,std::unique_ptr<DistributedFS::FDGuard> fdg,int64_t fp)96 static NVal InstantiateRandomAccessFile(napi_env env, std::unique_ptr<DistributedFS::FDGuard> fdg, int64_t fp)
97 {
98     napi_value objRAF = NClass::InstantiateClass(env, RandomAccessFileNExporter::className_, {});
99     if (!objRAF) {
100         HILOGE("Cannot instantiate randomaccessfile");
101         NError(EIO).ThrowErr(env);
102         return NVal();
103     }
104     auto rafEntity = NClass::GetEntityOf<RandomAccessFileEntity>(env, objRAF);
105     if (!rafEntity) {
106         HILOGE("Cannot instantiate randomaccessfile because of void entity");
107         NError(EIO).ThrowErr(env);
108         return NVal();
109     }
110     rafEntity->fd.swap(fdg);
111     rafEntity->filePointer = fp;
112     return { env, objRAF };
113 }
114 
Sync(napi_env env,napi_callback_info info)115 napi_value CreateRandomAccessFile::Sync(napi_env env, napi_callback_info info)
116 {
117     NFuncArg funcArg(env, info);
118     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
119         HILOGE("Number of arguments unmatched");
120         NError(EINVAL).ThrowErr(env);
121         return nullptr;
122     }
123     auto [succ, fileInfo, err] = ParseJsFile(env, funcArg[NARG_POS::FIRST]);
124     if (!succ) {
125         NError(err).ThrowErr(env);
126         return nullptr;
127     }
128     if (fileInfo.isPath) {
129         auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo);
130         if (!succFlags) {
131             return nullptr;
132         }
133         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
134             new uv_fs_t, CommonFunc::fs_req_cleanup };
135         if (!open_req) {
136             HILOGE("Failed to request heap memory.");
137             NError(ENOMEM).ThrowErr(env);
138             return nullptr;
139         }
140         int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), flags, S_IRUSR |
141             S_IWUSR | S_IRGRP | S_IWGRP, NULL);
142         if (ret < 0) {
143             NError(ret).ThrowErr(env);
144             return nullptr;
145         }
146 
147         fileInfo.fdg->SetFD(open_req.get()->result, false);
148     }
149     return InstantiateRandomAccessFile(env, move(fileInfo.fdg), 0).val_;
150 }
151 
152 struct AsyncCreateRandomAccessFileArg {
153     int fd = 0;
154 };
155 
AsyncExec(shared_ptr<AsyncCreateRandomAccessFileArg> arg,shared_ptr<FileInfo> fileInfo,unsigned int flags)156 NError AsyncExec(shared_ptr<AsyncCreateRandomAccessFileArg> arg,
157     shared_ptr<FileInfo> fileInfo, unsigned int flags)
158 {
159     if (fileInfo->isPath) {
160         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
161             new uv_fs_t, CommonFunc::fs_req_cleanup };
162         int ret = uv_fs_open(nullptr, open_req.get(), fileInfo->path.get(), flags, S_IRUSR |
163             S_IWUSR | S_IRGRP | S_IWGRP, NULL);
164         if (ret < 0) {
165             return NError(ret);
166         }
167         fileInfo->fdg->SetFD(open_req.get()->result, false);
168     }
169     arg->fd = fileInfo->fdg->GetFD();
170     return NError(ERRNO_NOERR);
171 }
172 
Async(napi_env env,napi_callback_info info)173 napi_value CreateRandomAccessFile::Async(napi_env env, napi_callback_info info)
174 {
175     NFuncArg funcArg(env, info);
176     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
177         HILOGE("Number of arguments unmatched");
178         NError(EINVAL).ThrowErr(env);
179         return nullptr;
180     }
181     auto [succ, fileInfo, err] = ParseJsFile(env, funcArg[NARG_POS::FIRST]);
182     if (!succ) {
183         NError(err).ThrowErr(env);
184         return nullptr;
185     }
186     auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo);
187     if (!succFlags) {
188         return nullptr;
189     }
190     auto arg = CreateSharedPtr<AsyncCreateRandomAccessFileArg>();
191     if (arg == nullptr) {
192         HILOGE("Failed to request heap memory.");
193         NError(ENOMEM).ThrowErr(env);
194         return nullptr;
195     }
196     auto movedFileInfo = CreateSharedPtr<FileInfo>(move(fileInfo));
197     if (movedFileInfo == nullptr) {
198         HILOGE("Failed to request heap memory.");
199         NError(ENOMEM).ThrowErr(env);
200         return nullptr;
201     }
202     auto cbExec = [arg, movedFileInfo, flags = flags]() -> NError {
203         return AsyncExec(arg, movedFileInfo, flags);
204     };
205 
206     auto cbCompl = [arg, movedFileInfo](napi_env env, NError err) -> NVal {
207         if (err) {
208             return { env, err.GetNapiErr(env) };
209         }
210         return InstantiateRandomAccessFile(env, move(movedFileInfo->fdg), 0);
211     };
212     NVal thisVar(env, funcArg.GetThisVar());
213     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
214         NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number))) {
215         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_CREATERAT_NAME, cbExec, cbCompl).val_;
216     } else {
217         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD);
218         NVal cb(env, funcArg[cbIdx]);
219         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_CREATERAT_NAME, cbExec, cbCompl).val_;
220     }
221 }
222 } // namespace ModuleFileIO
223 } // namespace FileManagement
224 } // namespace OHOS