• 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 
16 #include "randomaccessfile_n_exporter.h"
17 
18 #include "file_utils.h"
19 #include "randomaccessfile_entity.h"
20 #include "../common_func.h"
21 
22 namespace OHOS {
23 namespace FileManagement {
24 namespace ModuleFileIO {
25 using namespace std;
26 using namespace OHOS::FileManagement::LibN;
27 
GetRAFEntity(napi_env env,napi_value raf_entity)28 static tuple<bool, RandomAccessFileEntity*> GetRAFEntity(napi_env env, napi_value raf_entity)
29 {
30     auto rafEntity = NClass::GetEntityOf<RandomAccessFileEntity>(env, raf_entity);
31     if (!rafEntity) {
32         return { false, nullptr };
33     }
34     return { true, rafEntity };
35 }
36 
DoReadRAF(napi_env env,void * buf,size_t len,int fd,int64_t offset)37 static int DoReadRAF(napi_env env, void* buf, size_t len, int fd, int64_t offset)
38 {
39     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> read_req = {
40         new (nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
41     if (read_req == nullptr) {
42         HILOGE("Failed to request heap memory.");
43         return ENOMEM;
44     }
45     uv_buf_t iov = uv_buf_init(static_cast<char *>(buf), len);
46     int ret = uv_fs_read(nullptr, read_req.get(), fd, &iov, 1, offset, nullptr);
47     return ret;
48 }
49 
DoWriteRAF(napi_env env,void * buf,size_t len,int fd,int64_t offset)50 static int DoWriteRAF(napi_env env, void* buf, size_t len, int fd, int64_t offset)
51 {
52     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> write_req = {
53         new (nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
54     if (write_req == nullptr) {
55         HILOGE("Failed to request heap memory.");
56         return ENOMEM;
57     }
58     uv_buf_t iov = uv_buf_init(static_cast<char *>(buf), len);
59     int ret = uv_fs_write(nullptr, write_req.get(), fd, &iov, 1, offset, nullptr);
60     return ret;
61 }
62 
GetFD(napi_env env,napi_callback_info info)63 napi_value RandomAccessFileNExporter::GetFD(napi_env env, napi_callback_info info)
64 {
65     NFuncArg funcArg(env, info);
66     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
67         HILOGE("Number of arguments unmatched");
68         NError(EINVAL).ThrowErr(env);
69         return nullptr;
70     }
71     auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
72     if (!succEntity) {
73         HILOGE("Failed to get entity of RandomAccessFile");
74         NError(EIO).ThrowErr(env);
75         return nullptr;
76     }
77     return NVal::CreateInt32(env, rafEntity->fd.get()->GetFD()).val_;
78 }
79 
GetFPointer(napi_env env,napi_callback_info info)80 napi_value RandomAccessFileNExporter::GetFPointer(napi_env env, napi_callback_info info)
81 {
82     NFuncArg funcArg(env, info);
83     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
84         HILOGE("Number of arguments unmatched");
85         NError(EINVAL).ThrowErr(env);
86         return nullptr;
87     }
88     auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
89     if (!succEntity) {
90         HILOGE("Failed to get entity of RandomAccessFile");
91         NError(EIO).ThrowErr(env);
92         return nullptr;
93     }
94     return NVal::CreateInt64(env, rafEntity->filePointer).val_;
95 }
96 
SetFilePointerSync(napi_env env,napi_callback_info info)97 napi_value RandomAccessFileNExporter::SetFilePointerSync(napi_env env, napi_callback_info info)
98 {
99     NFuncArg funcArg(env, info);
100     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
101         HILOGE("Number of arguments unmatched");
102         NError(EINVAL).ThrowErr(env);
103         return nullptr;
104     }
105     auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
106     if (!succEntity) {
107         HILOGE("Failed to get entity of RandomAccessFile");
108         NError(EIO).ThrowErr(env);
109         return nullptr;
110     }
111     auto [succ, fp] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt64();
112     if (!succ) {
113         HILOGE("Invalid filePointer");
114         NError(EINVAL).ThrowErr(env);
115         return nullptr;
116     }
117     rafEntity->filePointer = fp;
118     return NVal::CreateUndefined(env).val_;
119 }
120 
CalculateOffset(int64_t offset,int64_t fPointer)121 static int64_t CalculateOffset(int64_t offset, int64_t fPointer)
122 {
123     if (offset < 0) {
124         HILOGI("No specified offset provided");
125         offset = fPointer;
126     } else {
127         offset += fPointer;
128     }
129     return offset;
130 }
131 
ReadSync(napi_env env,napi_callback_info info)132 napi_value RandomAccessFileNExporter::ReadSync(napi_env env, napi_callback_info info)
133 {
134     NFuncArg funcArg(env, info);
135     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
136         HILOGE("Number of arguments unmatched");
137         NError(EINVAL).ThrowErr(env);
138         return nullptr;
139     }
140     auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
141     if (!succEntity) {
142         HILOGE("Failed to get entity of RandomAccessFile");
143         NError(EIO).ThrowErr(env);
144         return nullptr;
145     }
146     auto [succ, buf, len, offset] =
147         CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
148     if (!succ) {
149         HILOGE("Invalid buffer/options");
150         NError(EINVAL).ThrowErr(env);
151         return nullptr;
152     }
153     offset = CalculateOffset(offset, rafEntity->filePointer);
154     int actLen = DoReadRAF(env, buf, len, rafEntity->fd.get()->GetFD(), offset);
155     if (actLen < 0) {
156         HILOGE("Failed to read file for %{public}d", actLen);
157         NError(actLen).ThrowErr(env);
158         return nullptr;
159     }
160     rafEntity->filePointer = offset + actLen;
161     return NVal::CreateInt64(env, actLen).val_;
162 }
163 
164 struct AsyncIORafReadArg {
165     int lenRead { 0 };
166     NRef rafRefReadBuf;
167 
AsyncIORafReadArgOHOS::FileManagement::ModuleFileIO::AsyncIORafReadArg168     explicit AsyncIORafReadArg(NVal jsReadBuf) : rafRefReadBuf(jsReadBuf) {}
169     ~AsyncIORafReadArg() = default;
170 };
171 
ReadExec(napi_env env,NFuncArg & funcArg,RandomAccessFileEntity * rafEntity)172 static napi_value ReadExec(napi_env env, NFuncArg &funcArg, RandomAccessFileEntity* rafEntity)
173 {
174     bool succ = false;
175     void *buf = nullptr;
176     size_t len = 0;
177     int64_t offset = 0;
178     tie(succ, buf, len, offset) = CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
179     if (!succ) {
180         HILOGE("Invalid buffer/options");
181         NError(EINVAL).ThrowErr(env);
182         return nullptr;
183     }
184 
185     auto arg = CreateSharedPtr<AsyncIORafReadArg>(NVal(env, funcArg[NARG_POS::FIRST]));
186     if (arg == nullptr) {
187         HILOGE("Failed to request heap memory.");
188         NError(ENOMEM).ThrowErr(env);
189         return nullptr;
190     }
191     offset = CalculateOffset(offset, rafEntity->filePointer);
192     auto cbExec = [env, arg, buf, len, offset, rafEntity]() -> NError {
193         if (!rafEntity || !rafEntity->fd.get()) {
194             HILOGE("RandomAccessFile has been closed in read cbExec possibly");
195             return NError(EIO);
196         }
197         int actLen = DoReadRAF(env, buf, len, rafEntity->fd.get()->GetFD(), offset);
198         if (actLen < 0) {
199             return NError(actLen);
200         }
201         arg->lenRead = actLen;
202         rafEntity->filePointer = offset + actLen;
203         return NError(ERRNO_NOERR);
204     };
205     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
206         if (err) {
207             return { env, err.GetNapiErr(env) };
208         }
209         return { NVal::CreateInt64(env, static_cast<int64_t>(arg->lenRead)) };
210     };
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_function))) {
215         return NAsyncWorkPromise(env, thisVar).Schedule(readProcedureName, 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(readProcedureName, cbExec, cbCompl).val_;
220     }
221 }
222 
Read(napi_env env,napi_callback_info info)223 napi_value RandomAccessFileNExporter::Read(napi_env env, napi_callback_info info)
224 {
225     NFuncArg funcArg(env, info);
226     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
227         HILOGE("Number of arguments unmatched");
228         NError(EINVAL).ThrowErr(env);
229         return nullptr;
230     }
231     auto[succ, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
232     if (!succ) {
233         HILOGE("Failed to get entity of RandomAccessFile");
234         NError(EIO).ThrowErr(env);
235         return nullptr;
236     }
237     return ReadExec(env, funcArg, rafEntity);
238 }
239 
WriteSync(napi_env env,napi_callback_info info)240 napi_value RandomAccessFileNExporter::WriteSync(napi_env env, napi_callback_info info)
241 {
242     NFuncArg funcArg(env, info);
243     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
244         HILOGE("Number of arguments unmatched");
245         NError(EINVAL).ThrowErr(env);
246         return nullptr;
247     }
248     auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
249     if (!succEntity) {
250         HILOGE("Failed to get entity of RandomAccessFile");
251         NError(EIO).ThrowErr(env);
252         return nullptr;
253     }
254     auto [succ, ignore, buf, len, offset] =
255         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
256     if (!succ) {
257         HILOGE("Invalid buffer/options");
258         NError(EINVAL).ThrowErr(env);
259         return nullptr;
260     }
261     offset = CalculateOffset(offset, rafEntity->filePointer);
262     int writeLen = DoWriteRAF(env, buf, len, rafEntity->fd.get()->GetFD(), offset);
263     if (writeLen < 0) {
264         NError(writeLen).ThrowErr(env);
265         return nullptr;
266     }
267     rafEntity->filePointer = offset + writeLen;
268     return NVal::CreateInt64(env, writeLen).val_;
269 }
270 
271 struct AsyncIORafWriteArg {
272     NRef rafRefWriteArrayBuf;
273     int actLen = 0;
AsyncIORafWriteArgOHOS::FileManagement::ModuleFileIO::AsyncIORafWriteArg274     explicit AsyncIORafWriteArg(NVal refWriteArrayBuf) : rafRefWriteArrayBuf(refWriteArrayBuf) {}
275     ~AsyncIORafWriteArg() = default;
276 };
277 
WriteExec(napi_env env,NFuncArg & funcArg,RandomAccessFileEntity * rafEntity)278 static napi_value WriteExec(napi_env env, NFuncArg &funcArg, RandomAccessFileEntity* rafEntity)
279 {
280     bool succ = false;
281     void *buf = nullptr;
282     size_t len = 0;
283     int64_t offset = 0;
284     tie(succ, ignore, buf, len, offset) =
285         CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]);
286     if (!succ) {
287         HILOGE("Invalid buffer/options");
288         NError(EINVAL).ThrowErr(env);
289         return nullptr;
290     }
291 
292     auto arg = CreateSharedPtr<AsyncIORafWriteArg>(NVal(env, funcArg[NARG_POS::FIRST]));
293     if (arg == nullptr) {
294         HILOGE("Failed to request heap memory.");
295         NError(ENOMEM).ThrowErr(env);
296         return nullptr;
297     }
298     offset = CalculateOffset(offset, rafEntity->filePointer);
299     auto cbExec = [env, arg, buf, len, fd = rafEntity->fd.get()->GetFD(), offset, rafEntity]() -> NError {
300         if (!rafEntity || !rafEntity->fd.get()) {
301             HILOGE("RandomAccessFile has been closed in write cbExec possibly");
302             return NError(EIO);
303         }
304         int writeLen = DoWriteRAF(env, buf, len, fd, offset);
305         if (writeLen < 0) {
306             HILOGE("Failed to write file for %{public}d", writeLen);
307             return NError(writeLen);
308         }
309         arg->actLen = writeLen;
310         rafEntity->filePointer = offset + writeLen;
311         return NError(ERRNO_NOERR);
312     };
313 
314     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
315         if (err) {
316             return { env, err.GetNapiErr(env) };
317         } else {
318             return { NVal::CreateInt64(env, arg->actLen) };
319         }
320     };
321 
322     NVal thisVar(env, funcArg.GetThisVar());
323     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
324         !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) {
325         return NAsyncWorkPromise(env, thisVar).Schedule(writeProcedureName, cbExec, cbCompl).val_;
326     } else {
327         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD);
328         NVal cb(env, funcArg[cbIdx]);
329         return NAsyncWorkCallback(env, thisVar, cb).Schedule(writeProcedureName, cbExec, cbCompl).val_;
330     }
331 }
332 
Write(napi_env env,napi_callback_info info)333 napi_value RandomAccessFileNExporter::Write(napi_env env, napi_callback_info info)
334 {
335     NFuncArg funcArg(env, info);
336     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
337         HILOGE("Number of arguments unmatched");
338         NError(EINVAL).ThrowErr(env);
339         return nullptr;
340     }
341     auto[succ, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
342     if (!succ) {
343         HILOGE("Failed to get entity of RandomAccessFile");
344         NError(EIO).ThrowErr(env);
345         return nullptr;
346     }
347     return WriteExec(env, funcArg, rafEntity);
348 }
349 
CloseFd(int fd)350 static NError CloseFd(int fd)
351 {
352     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> close_req = {
353         new uv_fs_t, CommonFunc::fs_req_cleanup };
354     if (!close_req) {
355         HILOGE("Failed to request heap memory.");
356         return NError(ENOMEM);
357     }
358     int ret = uv_fs_close(nullptr, close_req.get(), fd, nullptr);
359     if (ret < 0) {
360         HILOGE("Failed to close file with ret: %{public}d", ret);
361         return NError(ret);
362     }
363     return NError(ERRNO_NOERR);
364 }
365 
CloseSync(napi_env env,napi_callback_info info)366 napi_value RandomAccessFileNExporter::CloseSync(napi_env env, napi_callback_info info)
367 {
368     NFuncArg funcArg(env, info);
369     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
370         HILOGE("Number of arguments unmatched");
371         NError(EINVAL).ThrowErr(env);
372         return nullptr;
373     }
374     auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar());
375     if (!succEntity) {
376         HILOGE("Failed to get entity of RandomAccessFile");
377         NError(EIO).ThrowErr(env);
378         return nullptr;
379     }
380     auto err = CloseFd(rafEntity->fd.get()->GetFD());
381     if (err) {
382         err.ThrowErr(env);
383         return nullptr;
384     }
385     auto fp = NClass::RemoveEntityOfFinal<RandomAccessFileEntity>(env, funcArg.GetThisVar());
386     if (!fp) {
387         HILOGE("Failed to remove entity of RandomAccessFile");
388         NError(EIO).ThrowErr(env);
389         return nullptr;
390     }
391     return NVal::CreateUndefined(env).val_;
392 }
393 
Constructor(napi_env env,napi_callback_info info)394 napi_value RandomAccessFileNExporter::Constructor(napi_env env, napi_callback_info info)
395 {
396     NFuncArg funcArg(env, info);
397     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
398         HILOGE("Number of arguments unmatched");
399         NError(EINVAL).ThrowErr(env);
400         return nullptr;
401     }
402 
403     auto rafEntity = CreateUniquePtr<RandomAccessFileEntity>();
404     if (rafEntity == nullptr) {
405         HILOGE("Failed to request heap memory.");
406         NError(ENOMEM).ThrowErr(env);
407         return nullptr;
408     }
409     if (!NClass::SetEntityFor<RandomAccessFileEntity>(env, funcArg.GetThisVar(), move(rafEntity))) {
410         HILOGE("INNER BUG. Failed to wrap entity for obj RandomAccessFile");
411         NError(EIO).ThrowErr(env);
412         return nullptr;
413     }
414     return funcArg.GetThisVar();
415 }
416 
Export()417 bool RandomAccessFileNExporter::Export()
418 {
419     vector<napi_property_descriptor> props = {
420         NVal::DeclareNapiFunction("read", Read),
421         NVal::DeclareNapiFunction("readSync", ReadSync),
422         NVal::DeclareNapiFunction("write", Write),
423         NVal::DeclareNapiFunction("writeSync", WriteSync),
424         NVal::DeclareNapiFunction("setFilePointer", SetFilePointerSync),
425         NVal::DeclareNapiFunction("close", CloseSync),
426         NVal::DeclareNapiGetter("fd", GetFD),
427         NVal::DeclareNapiGetter("filePointer", GetFPointer),
428     };
429 
430     string className = GetClassName();
431     bool succ = false;
432     napi_value classValue = nullptr;
433     tie(succ, classValue) = NClass::DefineClass(exports_.env_, className,
434         RandomAccessFileNExporter::Constructor, move(props));
435     if (!succ) {
436         HILOGE("INNER BUG. Failed to define class");
437         NError(EIO).ThrowErr(exports_.env_);
438         return false;
439     }
440     succ = NClass::SaveClass(exports_.env_, className, classValue);
441     if (!succ) {
442         HILOGE("INNER BUG. Failed to define class");
443         NError(EIO).ThrowErr(exports_.env_);
444         return false;
445     }
446 
447     return exports_.AddProp(className, classValue);
448 }
449 
GetClassName()450 string RandomAccessFileNExporter::GetClassName()
451 {
452     return RandomAccessFileNExporter::className_;
453 }
454 
RandomAccessFileNExporter(napi_env env,napi_value exports)455 RandomAccessFileNExporter::RandomAccessFileNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
456 
~RandomAccessFileNExporter()457 RandomAccessFileNExporter::~RandomAccessFileNExporter() {}
458 } // namespace ModuleFileIO
459 } // namespace FileManagement
460 } // namespace OHOS