diff --git a/interfaces/kits/js/BUILD.gn b/interfaces/kits/js/BUILD.gn index b13c97dba78f5946b8518093e4db6ccd5f967012..06e4a83d8dcc8bd15d502d52c27e3fc89d0bfa04 100644 --- a/interfaces/kits/js/BUILD.gn +++ b/interfaces/kits/js/BUILD.gn @@ -117,6 +117,7 @@ ohos_shared_library("fs") { sources = [ "src/common/file_helper/fd_guard.cpp", "src/mod_fs/class_file/file_n_exporter.cpp", + "src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.cpp", "src/mod_fs/class_stat/stat_n_exporter.cpp", "src/mod_fs/common_func.cpp", "src/mod_fs/module.cpp", @@ -154,6 +155,7 @@ ohos_shared_library("fs") { "src/mod_fs/class_watcher/watcher_n_exporter.cpp", "src/mod_fs/properties/copy_file.cpp", "src/mod_fs/properties/copydir.cpp", + "src/mod_fs/properties/create_randomaccessfile.cpp", "src/mod_fs/properties/create_stream.cpp", "src/mod_fs/properties/fdopen_stream.cpp", "src/mod_fs/properties/listfile.cpp", diff --git a/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_entity.h b/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_entity.h index 2081bffab3e3c07005c4a3077eb973c818c40c5a..6799cc2585b344d888456895ddf5e32c63a99675 100644 --- a/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_entity.h +++ b/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_entity.h @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H -#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H - -#include - -#include "../../common/file_helper/fd_guard.h" - -namespace OHOS { -namespace DistributedFS { -namespace ModuleFileIO { -struct RandomAccessFileEntity { - std::unique_ptr fd_; - size_t fpointer = 0; -}; -} // namespace ModuleFileIO -} // namespace DistributedFS -} // namespace OHOS -#endif \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H +#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H + +#include + +#include "../../common/file_helper/fd_guard.h" + +namespace OHOS { +namespace DistributedFS { +namespace ModuleFileIO { +struct RandomAccessFileEntity { + std::unique_ptr fd_; + size_t fpointer = 0; +}; +} // namespace ModuleFileIO +} // namespace DistributedFS +} // namespace OHOS +#endif diff --git a/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.cpp b/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.cpp index e5ff8f32b321cd3d2da21f2104dba7f8a7ae362d..4cfc027943ec7227b3d1ac653d09148fa83246ad 100644 --- a/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.cpp +++ b/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.cpp @@ -1,428 +1,428 @@ -/* - * Copyright (c) 2022-2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "randomaccessfile_n_exporter.h" - -#include -#include -#include -#include -#include -#include - -#include "../../common/log.h" -#include "../../common/napi/n_async/n_async_work_callback.h" -#include "../../common/napi/n_async/n_async_work_promise.h" -#include "../../common/napi/n_class.h" -#include "../../common/napi/n_func_arg.h" -#include "../../common/uni_error.h" -#include "../common_func.h" -#include "randomaccessfile_entity.h" - -namespace OHOS { -namespace DistributedFS { -namespace ModuleFileIO { -using namespace std; - -static RandomAccessFileEntity *GetRAFEntity(napi_env env, napi_value raf_entity) -{ - auto rafEntity = NClass::GetEntityOf(env, raf_entity); - if (!rafEntity) { - UniError(EINVAL).ThrowErr(env, "Cannot get entity of RandomAccessFile"); - return nullptr; - } - if (rafEntity->fd_ == 0) { - UniError(EINVAL).ThrowErr(env, "RandomAccessFile has been closed yet"); - return nullptr; - } - return rafEntity; -} - -static tuple ParseJsFP(napi_env env, napi_value FPFromJs) -{ - auto [succ, fp] = NVal(env, FPFromJs).ToInt32(); - return { succ, fp }; -} - -static tuple GetRAFReadArg(napi_env env, - napi_value ReadBuf, napi_value option) -{ - bool succ = false; - void *buf = nullptr; - size_t len = 0; - int64_t pos = -1; - int64_t offset = 0; - tie(succ, buf, len, pos, offset) = CommonFunc::GetReadArg(env, ReadBuf, option); - if (!succ) { - return { false, nullptr, 0, 0, 0 }; - } - return { true, buf, len, pos, offset }; -} - -static tuple GetRAFWriteArg(napi_env env, - napi_value WriteBuf, napi_value option) -{ - bool succ = false; - void *buf = nullptr; - size_t len = 0; - int64_t pos = -1; - tie(succ, ignore, buf, len, pos) = CommonFunc::GetWriteArg(env, WriteBuf, option); - if (!succ) { - return { false, nullptr, 0, 0 }; - } - return { true, buf, len, pos }; -} - -static int DoReadRAF(napi_env env, void* buf, size_t len, int fd, int64_t pos) -{ - uv_loop_s *loop = nullptr; - uv_fs_t read_req; - napi_get_uv_event_loop(env, &loop); - uv_buf_t iov = uv_buf_init(static_cast(buf), len); - int ret = uv_fs_read(loop, &read_req, fd, &iov, 1, pos, NULL); - uv_fs_req_cleanup(&read_req); - return ret; -} - -static size_t DoWriteRAF(napi_env env, void* buf, size_t len, int fd, int64_t pos) -{ - uv_loop_s *loop = nullptr; - uv_fs_t write_req; - napi_get_uv_event_loop(env, &loop); - uv_buf_t iov = uv_buf_init(static_cast(buf), len); - size_t ret = uv_fs_write(loop, &write_req, fd, &iov, 1, pos, NULL); - uv_fs_req_cleanup(&write_req); - return ret; -} - -napi_value RandomAccessFileNExporter::GetFD(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ZERO)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - return NVal::CreateInt32(env, rafEntity->fd_.get()->GetFD()).val_; -} - -napi_value RandomAccessFileNExporter::GetFPointer(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ZERO)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - return NVal::CreateInt64(env, rafEntity->fpointer).val_; -} - -napi_value RandomAccessFileNExporter::SetFilePointerSync(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - auto [succ, fp] = ParseJsFP(env, funcArg[NARG_POS::FIRST]); - if (!succ) { - UniError(EINVAL).ThrowErr(env, "Invalid fpointer"); - return nullptr; - } - rafEntity->fpointer = fp; - return NVal::CreateUndefined(env).val_; -} - -napi_value RandomAccessFileNExporter::ReadSync(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - auto [succ, buf, len, pos, ignore] = - GetRAFReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); - if (!succ) { - UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); - return nullptr; - } - int actLen = DoReadRAF(env, buf, len, rafEntity->fd_.get()->GetFD(), rafEntity->fpointer + pos); - if (actLen < 0) { - UniError(errno).ThrowErr(env); - return nullptr; - } - rafEntity->fpointer += actLen; - return NVal::CreateInt64(env, actLen).val_; -} - -struct AsyncIOReadArg { - size_t lenRead { 0 }; - int64_t offset { 0 }; - NRef refReadBuf; - - explicit AsyncIOReadArg(NVal jsReadBuf) : refReadBuf(jsReadBuf) {} - ~AsyncIOReadArg() = default; -}; - -static napi_value ReadExec(napi_env env, NFuncArg &funcArg) -{ - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - bool succ = false; - size_t len = 0; - int64_t pos = -1; - int64_t offset = 0; - void* buf = nullptr; - tie(succ, buf, len, pos, offset) = GetRAFReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); - if (!succ) { - UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); - return nullptr; - } - - auto arg = make_shared(NVal(env, funcArg[NARG_POS::FIRST])); - auto cbExec = [arg, buf, len, pos, offset, rafEntity](napi_env env) -> UniError { - int actLen = DoReadRAF(env, buf, len, rafEntity->fd_.get()->GetFD(), rafEntity->fpointer + pos); - if (actLen < 0) { - return UniError(errno); - } - arg->lenRead = actLen; - arg->offset = offset; - rafEntity->fpointer += actLen; - return UniError(ERRNO_NOERR); - }; - auto cbCompl = [arg](napi_env env, UniError err) -> NVal { - if (err) { - return { env, err.GetNapiErr(env) }; - } - NVal obj = NVal::CreateObject(env); - obj.AddProp( - { NVal::DeclareNapiProperty("bytesRead", NVal::CreateInt64(env, arg->lenRead).val_), - NVal::DeclareNapiProperty("buffer", arg->refReadBuf.Deref(env).val_), - NVal::DeclareNapiProperty("offset", NVal::CreateInt64(env, arg->offset).val_) - }); - return { obj }; - }; - - NVal thisVar(env, funcArg.GetThisVar()); - if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && - !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) { - return NAsyncWorkPromise(env, thisVar).Schedule(readProcedureName, cbExec, cbCompl).val_; - } else { - int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); - NVal cb(env, funcArg[cbIdx]); - return NAsyncWorkCallback(env, thisVar, cb).Schedule(readProcedureName, cbExec, cbCompl).val_; - } -} - -napi_value RandomAccessFileNExporter::Read(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - - return ReadExec(env, funcArg); -} - -napi_value RandomAccessFileNExporter::WriteSync(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - - bool succ = false; - void *buf = nullptr; - size_t len = 0; - int64_t pos = -1; - tie(succ, buf, len, pos) = GetRAFWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); - if (!succ) { - UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); - return nullptr; - } - if (pos >= 0) { - pos = rafEntity->fpointer + pos; - } else { - pos = rafEntity->fpointer; - } - ssize_t writeLen = DoWriteRAF(env, buf, len, rafEntity->fd_.get()->GetFD(), pos); - if (writeLen < 0) { - UniError(errno).ThrowErr(env); - return nullptr; - } - rafEntity->fpointer += writeLen; - return NVal::CreateInt64(env, writeLen).val_; -} - -struct AsyncIOWriteArg { - NRef refWriteArrayBuf_; - size_t actLen = 0; - explicit AsyncIOWriteArg(NVal refWriteArrayBuf) : refWriteArrayBuf_(refWriteArrayBuf) {} - ~AsyncIOWriteArg() = default; -}; - -napi_value RandomAccessFileNExporter::Write(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - bool succ = false; - void *buf = nullptr; - size_t len = 0; - int64_t pos = -1; - tie(succ, buf, len, pos) = GetRAFWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); - if (!succ) { - UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); - return nullptr; - } - if (pos >= 0) { - pos = rafEntity->fpointer + pos; - } else { - pos = rafEntity->fpointer; - } - - auto arg = make_shared(NVal(env, funcArg[NARG_POS::FIRST])); - auto cbExec = [arg, buf, len, fd = rafEntity->fd_.get()->GetFD(), pos, rafEntity](napi_env env) -> UniError { - size_t writeLen = DoWriteRAF(env, buf, len, fd, pos); - if (writeLen < 0) { - return UniError(errno); - } - arg->actLen = writeLen; - rafEntity->fpointer += writeLen; - return UniError(ERRNO_NOERR); - }; - - auto cbCompl = [arg](napi_env env, UniError err) -> NVal { - if (err) { - return { env, err.GetNapiErr(env) }; - } else { - return { NVal::CreateInt64(env, arg->actLen) }; - } - }; - - NVal thisVar(env, funcArg.GetThisVar()); - if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && - !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) { - return NAsyncWorkPromise(env, thisVar).Schedule(writeProcedureName, cbExec, cbCompl).val_; - } else { - int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); - NVal cb(env, funcArg[cbIdx]); - return NAsyncWorkCallback(env, thisVar, cb).Schedule(writeProcedureName, cbExec, cbCompl).val_; - } -} - -napi_value RandomAccessFileNExporter::CloseSync(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ZERO)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); - if (!rafEntity) { - return nullptr; - } - rafEntity->fd_.reset(); - return NVal::CreateUndefined(env).val_; -} - -napi_value RandomAccessFileNExporter::Constructor(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::ZERO)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - - auto rafEntity = make_unique(); - if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(rafEntity))) { - UniError(EIO).ThrowErr(env, "INNER BUG. Failed to wrap entity for obj RandomAccessFile"); - return nullptr; - } - return funcArg.GetThisVar(); -} - -bool RandomAccessFileNExporter::Export() -{ - vector props = { - NVal::DeclareNapiFunction("read", Read), - NVal::DeclareNapiFunction("readSync", ReadSync), - NVal::DeclareNapiFunction("write", Write), - NVal::DeclareNapiFunction("writeSync", WriteSync), - NVal::DeclareNapiFunction("setFilePointerSync", SetFilePointerSync), - NVal::DeclareNapiFunction("closeSync", CloseSync), - NVal::DeclareNapiGetter("fd", GetFD), - NVal::DeclareNapiGetter("fpointer", GetFPointer), - }; - - string className = GetClassName(); - bool succ = false; - napi_value classValue = nullptr; - tie(succ, classValue) = NClass::DefineClass(exports_.env_, className, - RandomAccessFileNExporter::Constructor, move(props)); - if (!succ) { - UniError(EIO).ThrowErr(exports_.env_, "INNER BUG. Failed to define class"); - return false; - } - succ = NClass::SaveClass(exports_.env_, className, classValue); - if (!succ) { - UniError(EIO).ThrowErr(exports_.env_, "INNER BUG. Failed to save class"); - return false; - } - - return exports_.AddProp(className, classValue); -} - -string RandomAccessFileNExporter::GetClassName() -{ - return RandomAccessFileNExporter::className_; -} - -RandomAccessFileNExporter::RandomAccessFileNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {} - -RandomAccessFileNExporter::~RandomAccessFileNExporter() {} -} // namespace ModuleFileIO -} // namespace DistributedFS -} // namespace OHOS \ No newline at end of file +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "randomaccessfile_n_exporter.h" + +#include +#include +#include +#include +#include +#include + +#include "../../common/log.h" +#include "../../common/napi/n_async/n_async_work_callback.h" +#include "../../common/napi/n_async/n_async_work_promise.h" +#include "../../common/napi/n_class.h" +#include "../../common/napi/n_func_arg.h" +#include "../../common/uni_error.h" +#include "../common_func.h" +#include "randomaccessfile_entity.h" + +namespace OHOS { +namespace DistributedFS { +namespace ModuleFileIO { +using namespace std; + +static RandomAccessFileEntity *GetRAFEntity(napi_env env, napi_value raf_entity) +{ + auto rafEntity = NClass::GetEntityOf(env, raf_entity); + if (!rafEntity) { + UniError(EINVAL).ThrowErr(env, "Cannot get entity of RandomAccessFile"); + return nullptr; + } + if (rafEntity->fd_ == 0) { + UniError(EINVAL).ThrowErr(env, "RandomAccessFile has been closed yet"); + return nullptr; + } + return rafEntity; +} + +static tuple ParseJsFP(napi_env env, napi_value FPFromJs) +{ + auto [succ, fp] = NVal(env, FPFromJs).ToInt32(); + return { succ, fp }; +} + +static tuple GetRAFReadArg(napi_env env, + napi_value ReadBuf, napi_value option) +{ + bool succ = false; + void *buf = nullptr; + size_t len = 0; + int64_t pos = -1; + int64_t offset = 0; + tie(succ, buf, len, pos, offset) = CommonFunc::GetReadArg(env, ReadBuf, option); + if (!succ) { + return { false, nullptr, 0, 0, 0 }; + } + return { true, buf, len, pos, offset }; +} + +static tuple GetRAFWriteArg(napi_env env, + napi_value WriteBuf, napi_value option) +{ + bool succ = false; + void *buf = nullptr; + size_t len = 0; + int64_t pos = -1; + tie(succ, ignore, buf, len, pos) = CommonFunc::GetWriteArg(env, WriteBuf, option); + if (!succ) { + return { false, nullptr, 0, 0 }; + } + return { true, buf, len, pos }; +} + +static int DoReadRAF(napi_env env, void* buf, size_t len, int fd, int64_t pos) +{ + uv_loop_s *loop = nullptr; + uv_fs_t read_req; + napi_get_uv_event_loop(env, &loop); + uv_buf_t iov = uv_buf_init(static_cast(buf), len); + int ret = uv_fs_read(loop, &read_req, fd, &iov, 1, pos, NULL); + uv_fs_req_cleanup(&read_req); + return ret; +} + +static size_t DoWriteRAF(napi_env env, void* buf, size_t len, int fd, int64_t pos) +{ + uv_loop_s *loop = nullptr; + uv_fs_t write_req; + napi_get_uv_event_loop(env, &loop); + uv_buf_t iov = uv_buf_init(static_cast(buf), len); + size_t ret = uv_fs_write(loop, &write_req, fd, &iov, 1, pos, NULL); + uv_fs_req_cleanup(&write_req); + return ret; +} + +napi_value RandomAccessFileNExporter::GetFD(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + return NVal::CreateInt32(env, rafEntity->fd_.get()->GetFD()).val_; +} + +napi_value RandomAccessFileNExporter::GetFPointer(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + return NVal::CreateInt64(env, rafEntity->fpointer).val_; +} + +napi_value RandomAccessFileNExporter::SetFilePointerSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + auto [succ, fp] = ParseJsFP(env, funcArg[NARG_POS::FIRST]); + if (!succ) { + UniError(EINVAL).ThrowErr(env, "Invalid fpointer"); + return nullptr; + } + rafEntity->fpointer = fp; + return NVal::CreateUndefined(env).val_; +} + +napi_value RandomAccessFileNExporter::ReadSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + auto [succ, buf, len, pos, ignore] = + GetRAFReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); + return nullptr; + } + int actLen = DoReadRAF(env, buf, len, rafEntity->fd_.get()->GetFD(), rafEntity->fpointer + pos); + if (actLen < 0) { + UniError(errno).ThrowErr(env); + return nullptr; + } + rafEntity->fpointer += actLen; + return NVal::CreateInt64(env, actLen).val_; +} + +struct AsyncIOReadArg { + size_t lenRead { 0 }; + int64_t offset { 0 }; + NRef refReadBuf; + + explicit AsyncIOReadArg(NVal jsReadBuf) : refReadBuf(jsReadBuf) {} + ~AsyncIOReadArg() = default; +}; + +static napi_value ReadExec(napi_env env, NFuncArg &funcArg) +{ + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + bool succ = false; + size_t len = 0; + int64_t pos = -1; + int64_t offset = 0; + void* buf = nullptr; + tie(succ, buf, len, pos, offset) = GetRAFReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); + return nullptr; + } + + auto arg = make_shared(NVal(env, funcArg[NARG_POS::FIRST])); + auto cbExec = [arg, buf, len, pos, offset, rafEntity](napi_env env) -> UniError { + int actLen = DoReadRAF(env, buf, len, rafEntity->fd_.get()->GetFD(), rafEntity->fpointer + pos); + if (actLen < 0) { + return UniError(errno); + } + arg->lenRead = actLen; + arg->offset = offset; + rafEntity->fpointer += actLen; + return UniError(ERRNO_NOERR); + }; + auto cbCompl = [arg](napi_env env, UniError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + NVal obj = NVal::CreateObject(env); + obj.AddProp( + { NVal::DeclareNapiProperty("bytesRead", NVal::CreateInt64(env, arg->lenRead).val_), + NVal::DeclareNapiProperty("buffer", arg->refReadBuf.Deref(env).val_), + NVal::DeclareNapiProperty("offset", NVal::CreateInt64(env, arg->offset).val_) + }); + return { obj }; + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && + !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) { + return NAsyncWorkPromise(env, thisVar).Schedule(readProcedureName, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(readProcedureName, cbExec, cbCompl).val_; + } +} + +napi_value RandomAccessFileNExporter::Read(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + return ReadExec(env, funcArg); +} + +napi_value RandomAccessFileNExporter::WriteSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + + bool succ = false; + void *buf = nullptr; + size_t len = 0; + int64_t pos = -1; + tie(succ, buf, len, pos) = GetRAFWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); + return nullptr; + } + if (pos >= 0) { + pos = rafEntity->fpointer + pos; + } else { + pos = rafEntity->fpointer; + } + ssize_t writeLen = DoWriteRAF(env, buf, len, rafEntity->fd_.get()->GetFD(), pos); + if (writeLen < 0) { + UniError(errno).ThrowErr(env); + return nullptr; + } + rafEntity->fpointer += writeLen; + return NVal::CreateInt64(env, writeLen).val_; +} + +struct AsyncIOWriteArg { + NRef refWriteArrayBuf_; + size_t actLen = 0; + explicit AsyncIOWriteArg(NVal refWriteArrayBuf) : refWriteArrayBuf_(refWriteArrayBuf) {} + ~AsyncIOWriteArg() = default; +}; + +napi_value RandomAccessFileNExporter::Write(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + bool succ = false; + void *buf = nullptr; + size_t len = 0; + int64_t pos = -1; + tie(succ, buf, len, pos) = GetRAFWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + UniError(EINVAL).ThrowErr(env, "Invalid buffer/options"); + return nullptr; + } + if (pos >= 0) { + pos = rafEntity->fpointer + pos; + } else { + pos = rafEntity->fpointer; + } + + auto arg = make_shared(NVal(env, funcArg[NARG_POS::FIRST])); + auto cbExec = [arg, buf, len, fd = rafEntity->fd_.get()->GetFD(), pos, rafEntity](napi_env env) -> UniError { + size_t writeLen = DoWriteRAF(env, buf, len, fd, pos); + if (writeLen < 0) { + return UniError(errno); + } + arg->actLen = writeLen; + rafEntity->fpointer += writeLen; + return UniError(ERRNO_NOERR); + }; + + auto cbCompl = [arg](napi_env env, UniError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return { NVal::CreateInt64(env, arg->actLen) }; + } + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && + !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) { + return NAsyncWorkPromise(env, thisVar).Schedule(writeProcedureName, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(writeProcedureName, cbExec, cbCompl).val_; + } +} + +napi_value RandomAccessFileNExporter::CloseSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto rafEntity = GetRAFEntity(env, funcArg.GetThisVar()); + if (!rafEntity) { + return nullptr; + } + rafEntity->fd_.reset(); + return NVal::CreateUndefined(env).val_; +} + +napi_value RandomAccessFileNExporter::Constructor(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + + auto rafEntity = make_unique(); + if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(rafEntity))) { + UniError(EIO).ThrowErr(env, "INNER BUG. Failed to wrap entity for obj RandomAccessFile"); + return nullptr; + } + return funcArg.GetThisVar(); +} + +bool RandomAccessFileNExporter::Export() +{ + vector props = { + NVal::DeclareNapiFunction("read", Read), + NVal::DeclareNapiFunction("readSync", ReadSync), + NVal::DeclareNapiFunction("write", Write), + NVal::DeclareNapiFunction("writeSync", WriteSync), + NVal::DeclareNapiFunction("setFilePointerSync", SetFilePointerSync), + NVal::DeclareNapiFunction("closeSync", CloseSync), + NVal::DeclareNapiGetter("fd", GetFD), + NVal::DeclareNapiGetter("fpointer", GetFPointer), + }; + + string className = GetClassName(); + bool succ = false; + napi_value classValue = nullptr; + tie(succ, classValue) = NClass::DefineClass(exports_.env_, className, + RandomAccessFileNExporter::Constructor, move(props)); + if (!succ) { + UniError(EIO).ThrowErr(exports_.env_, "INNER BUG. Failed to define class"); + return false; + } + succ = NClass::SaveClass(exports_.env_, className, classValue); + if (!succ) { + UniError(EIO).ThrowErr(exports_.env_, "INNER BUG. Failed to save class"); + return false; + } + + return exports_.AddProp(className, classValue); +} + +string RandomAccessFileNExporter::GetClassName() +{ + return RandomAccessFileNExporter::className_; +} + +RandomAccessFileNExporter::RandomAccessFileNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {} + +RandomAccessFileNExporter::~RandomAccessFileNExporter() {} +} // namespace ModuleFileIO +} // namespace DistributedFS +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.h b/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.h index bd89a1b9c9d581bbff8a1bae84f1d481b5753e23..ca33d9356c744cb30250a3924821e17c0f06b746 100644 --- a/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.h +++ b/interfaces/kits/js/src/mod_fileio/class_randomaccessfile/randomaccessfile_n_exporter.h @@ -1,52 +1,52 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_N_EXPORTER_H -#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_N_EXPORTER_H - -#include "../../common/napi/n_exporter.h" - -namespace OHOS { -namespace DistributedFS { -namespace ModuleFileIO { -class RandomAccessFileNExporter final : public NExporter { -public: - inline static const std::string className_ = "RandomAccessFile"; - - bool Export() override; - std::string GetClassName() override; - - static napi_value Constructor(napi_env env, napi_callback_info cbinfo); - - static napi_value SetFilePointerSync(napi_env env, napi_callback_info cbinfo); - static napi_value WriteSync(napi_env env, napi_callback_info cbinfo); - static napi_value ReadSync(napi_env env, napi_callback_info cbinfo); - static napi_value CloseSync(napi_env env, napi_callback_info cbinfo); - - static napi_value Write(napi_env env, napi_callback_info cbinfo); - static napi_value Read(napi_env env, napi_callback_info cbinfo); - - static napi_value GetFD(napi_env env, napi_callback_info cbinfo); - static napi_value GetFPointer(napi_env env, napi_callback_info cbinfo); - - RandomAccessFileNExporter(napi_env env, napi_value exports); - ~RandomAccessFileNExporter() override; -}; -const std::string readProcedureName = "FileIORandomAccessFileRead"; -const std::string writeProcedureName = "FileIORandomAccessFileWrite"; -} // namespace ModuleFileIO -} // namespace DistributedFS -} // namespace OHOS -#endif \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_N_EXPORTER_H +#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_N_EXPORTER_H + +#include "../../common/napi/n_exporter.h" + +namespace OHOS { +namespace DistributedFS { +namespace ModuleFileIO { +class RandomAccessFileNExporter final : public NExporter { +public: + inline static const std::string className_ = "RandomAccessFile"; + + bool Export() override; + std::string GetClassName() override; + + static napi_value Constructor(napi_env env, napi_callback_info cbinfo); + + static napi_value SetFilePointerSync(napi_env env, napi_callback_info cbinfo); + static napi_value WriteSync(napi_env env, napi_callback_info cbinfo); + static napi_value ReadSync(napi_env env, napi_callback_info cbinfo); + static napi_value CloseSync(napi_env env, napi_callback_info cbinfo); + + static napi_value Write(napi_env env, napi_callback_info cbinfo); + static napi_value Read(napi_env env, napi_callback_info cbinfo); + + static napi_value GetFD(napi_env env, napi_callback_info cbinfo); + static napi_value GetFPointer(napi_env env, napi_callback_info cbinfo); + + RandomAccessFileNExporter(napi_env env, napi_value exports); + ~RandomAccessFileNExporter() override; +}; +const std::string readProcedureName = "FileIORandomAccessFileRead"; +const std::string writeProcedureName = "FileIORandomAccessFileWrite"; +} // namespace ModuleFileIO +} // namespace DistributedFS +} // namespace OHOS +#endif diff --git a/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.cpp b/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.cpp index 0951fe5ca97fe7ffd1e9be4b01eb309384fc5b0c..1ef99e9fe21395dc3c6bc83c2489e01b786fcf5a 100644 --- a/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.cpp +++ b/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.cpp @@ -1,213 +1,213 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "create_randomaccessfile.h" - -#include -#include -#include -#include -#include -#include - -#include "../../common/log.h" -#include "../../common/napi/n_async/n_async_work_callback.h" -#include "../../common/napi/n_async/n_async_work_promise.h" -#include "../../common/napi/n_class.h" -#include "../../common/napi/n_func_arg.h" -#include "../../common/uni_error.h" -#include "../common_func.h" - -#include "../class_randomaccessfile/randomaccessfile_entity.h" -#include "../class_randomaccessfile/randomaccessfile_n_exporter.h" - -namespace OHOS { -namespace DistributedFS { -namespace ModuleFileIO { -using namespace std; - -struct FileInfo { - bool isPath = false; - unique_ptr path; - FDGuard fdg; -}; - -static bool CheckFilePath(napi_env env, string path) -{ - if (access(path.c_str(), 0) == 0) { - struct stat fileStat; - int ret = stat(path.c_str(), &fileStat); - if (ret != 0) { - UniError(errno).ThrowErr(env, "Cannot stat filepath"); - return false; - } - if ((fileStat.st_mode & S_IFMT) != S_IFREG) { - UniError(EINVAL).ThrowErr(env, "Invalid filepath"); - return false; - } - } - return true; -} - -static tuple ParseJsFileAndFP(napi_env env, napi_value pathOrFdFromJsArg, napi_value FPFromJs) -{ - auto [succ, fp] = NVal(env, FPFromJs).ToInt32(); - if (succ) { - auto [isPath, path, ignore] = NVal(env, pathOrFdFromJsArg).ToUTF8String(); - if (isPath) { - if (CheckFilePath(env, string(path.get()))) { - return { true, FileInfo { true, move(path), {} }, fp }; - } - return { false, FileInfo { false, {}, {} }, -1 }; - } - auto [isFd, fd] = NVal(env, pathOrFdFromJsArg).ToInt32(); - if (isFd) { - if (fd < 0) { - UniError(EINVAL).ThrowErr(env, "Invalid fd"); - return { false, FileInfo { false, {}, {} }, -1 }; - } - return { true, FileInfo { false, {}, { fd, false } }, fp }; - } - UniError(EINVAL).ThrowErr(env, "The first argument requires filepath/fd"); - } - UniError(EINVAL).ThrowErr(env, "Invalid fp"); - return { false, FileInfo { false, {}, {} }, -1 }; -}; - -static tuple GetJsFlags(napi_env env, const NFuncArg &funcArg, FileInfo &fileInfo) -{ - unsigned int flags = O_RDONLY; - if (fileInfo.isPath) { - if (funcArg.GetArgc() >= NARG_CNT::THREE && !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function)) { - auto [succ, mode] = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32(); - if (!succ || mode < 0) { - UniError(EINVAL).ThrowErr(env, "Invalid flags"); - return { false, flags }; - } - flags = static_cast(mode); - (void)CommonFunc::ConvertJsFlags(flags); - } - } - return { true, flags }; -} - -static NVal InstantiateRandomAccessFile(napi_env env, int fd, size_t fp) -{ - napi_value objRAF = NClass::InstantiateClass(env, RandomAccessFileNExporter::className_, {}); - if (!objRAF) { - UniError(EIO).ThrowErr(env, "Cannot instantiate randomaccessfile"); - return NVal(); - } - - auto rafEntity = NClass::GetEntityOf(env, objRAF); - if (!rafEntity) { - UniError(EIO).ThrowErr(env, "Cannot instantiate randomaccessfile because of void entity"); - return NVal(); - } - auto fdg = make_unique(fd); - rafEntity->fd_.swap(fdg); - rafEntity->fpointer = fp; - return { env, objRAF }; -} - -napi_value CreateRandomAccessFile::Sync(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto [succ, fileInfo, fp] = ParseJsFileAndFP(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); - if (!succ) { - return nullptr; - } - - if (fileInfo.isPath) { - auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo); - if (!succFlags) { - return nullptr; - } - uv_loop_s *loop = nullptr; - napi_get_uv_event_loop(env, &loop); - uv_fs_t openReq; - int ret = uv_fs_open(loop, &openReq, fileInfo.path.get(), flags, S_IRUSR | - S_IWUSR | S_IRGRP | S_IWGRP, NULL); - if (ret < 0) { - UniError(errno).ThrowErr(env); - return nullptr; - } - fileInfo.fdg.SetFD(openReq.result, false); - uv_fs_req_cleanup(&openReq); - } - return InstantiateRandomAccessFile(env, fileInfo.fdg.GetFD(), fp).val_; -} - -struct AsyncCreateRandomAccessFileArg { - int fd; - size_t fp; -}; - -napi_value CreateRandomAccessFile::Async(napi_env env, napi_callback_info info) -{ - NFuncArg funcArg(env, info); - if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) { - UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); - return nullptr; - } - auto [succ, fileInfo, fp] = ParseJsFileAndFP(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); - if (!succ) { - return nullptr; - } - auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo); - if (!succFlags) { - return nullptr; - } - auto arg = make_shared(); - auto cbExec = [arg, fileInfo = make_shared(move(fileInfo)), fp = fp, flags = - flags](napi_env env) -> UniError { - if (fileInfo->isPath) { - uv_loop_s *loop = nullptr; - napi_get_uv_event_loop(env, &loop); - uv_fs_t openReq; - int ret = uv_fs_open(loop, &openReq, fileInfo->path.get(), flags, S_IRUSR | - S_IWUSR | S_IRGRP | S_IWGRP, NULL); - if (ret < 0) { - return UniError(errno); - } - fileInfo->fdg.SetFD(openReq.result, false); - uv_fs_req_cleanup(&openReq); - } - arg->fd = fileInfo->fdg.GetFD(); - arg->fp = fp; - return UniError(ERRNO_NOERR); - }; - auto cbCompl = [arg](napi_env env, UniError err) -> NVal { - if (err) { - return { env, err.GetNapiErr(env) }; - } - return InstantiateRandomAccessFile(env, arg->fd, arg->fp); - }; - NVal thisVar(env, funcArg.GetThisVar()); - if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE && - NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number))) { - return NAsyncWorkPromise(env, thisVar).Schedule(createRAFProcedureName, cbExec, cbCompl).val_; - } else { - int cbIdx = ((funcArg.GetArgc() == NARG_CNT::FOUR) ? NARG_POS::FOURTH : NARG_POS::THIRD); - NVal cb(env, funcArg[cbIdx]); - return NAsyncWorkCallback(env, thisVar, cb).Schedule(createRAFProcedureName, cbExec, cbCompl).val_; - } -} -} // namespace ModuleFileIO -} // namespace DistributedFS -} // namespace OHOS \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "create_randomaccessfile.h" + +#include +#include +#include +#include +#include +#include + +#include "../../common/log.h" +#include "../../common/napi/n_async/n_async_work_callback.h" +#include "../../common/napi/n_async/n_async_work_promise.h" +#include "../../common/napi/n_class.h" +#include "../../common/napi/n_func_arg.h" +#include "../../common/uni_error.h" +#include "../common_func.h" + +#include "../class_randomaccessfile/randomaccessfile_entity.h" +#include "../class_randomaccessfile/randomaccessfile_n_exporter.h" + +namespace OHOS { +namespace DistributedFS { +namespace ModuleFileIO { +using namespace std; + +struct FileInfo { + bool isPath = false; + unique_ptr path; + FDGuard fdg; +}; + +static bool CheckFilePath(napi_env env, string path) +{ + if (access(path.c_str(), 0) == 0) { + struct stat fileStat; + int ret = stat(path.c_str(), &fileStat); + if (ret != 0) { + UniError(errno).ThrowErr(env, "Cannot stat filepath"); + return false; + } + if ((fileStat.st_mode & S_IFMT) != S_IFREG) { + UniError(EINVAL).ThrowErr(env, "Invalid filepath"); + return false; + } + } + return true; +} + +static tuple ParseJsFileAndFP(napi_env env, napi_value pathOrFdFromJsArg, napi_value FPFromJs) +{ + auto [succ, fp] = NVal(env, FPFromJs).ToInt32(); + if (succ) { + auto [isPath, path, ignore] = NVal(env, pathOrFdFromJsArg).ToUTF8String(); + if (isPath) { + if (CheckFilePath(env, string(path.get()))) { + return { true, FileInfo { true, move(path), {} }, fp }; + } + return { false, FileInfo { false, {}, {} }, -1 }; + } + auto [isFd, fd] = NVal(env, pathOrFdFromJsArg).ToInt32(); + if (isFd) { + if (fd < 0) { + UniError(EINVAL).ThrowErr(env, "Invalid fd"); + return { false, FileInfo { false, {}, {} }, -1 }; + } + return { true, FileInfo { false, {}, { fd, false } }, fp }; + } + UniError(EINVAL).ThrowErr(env, "The first argument requires filepath/fd"); + } + UniError(EINVAL).ThrowErr(env, "Invalid fp"); + return { false, FileInfo { false, {}, {} }, -1 }; +}; + +static tuple GetJsFlags(napi_env env, const NFuncArg &funcArg, FileInfo &fileInfo) +{ + unsigned int flags = O_RDONLY; + if (fileInfo.isPath) { + if (funcArg.GetArgc() >= NARG_CNT::THREE && !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function)) { + auto [succ, mode] = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32(); + if (!succ || mode < 0) { + UniError(EINVAL).ThrowErr(env, "Invalid flags"); + return { false, flags }; + } + flags = static_cast(mode); + (void)CommonFunc::ConvertJsFlags(flags); + } + } + return { true, flags }; +} + +static NVal InstantiateRandomAccessFile(napi_env env, int fd, size_t fp) +{ + napi_value objRAF = NClass::InstantiateClass(env, RandomAccessFileNExporter::className_, {}); + if (!objRAF) { + UniError(EIO).ThrowErr(env, "Cannot instantiate randomaccessfile"); + return NVal(); + } + + auto rafEntity = NClass::GetEntityOf(env, objRAF); + if (!rafEntity) { + UniError(EIO).ThrowErr(env, "Cannot instantiate randomaccessfile because of void entity"); + return NVal(); + } + auto fdg = make_unique(fd); + rafEntity->fd_.swap(fdg); + rafEntity->fpointer = fp; + return { env, objRAF }; +} + +napi_value CreateRandomAccessFile::Sync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto [succ, fileInfo, fp] = ParseJsFileAndFP(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + return nullptr; + } + + if (fileInfo.isPath) { + auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo); + if (!succFlags) { + return nullptr; + } + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(env, &loop); + uv_fs_t openReq; + int ret = uv_fs_open(loop, &openReq, fileInfo.path.get(), flags, S_IRUSR | + S_IWUSR | S_IRGRP | S_IWGRP, NULL); + if (ret < 0) { + UniError(errno).ThrowErr(env); + return nullptr; + } + fileInfo.fdg.SetFD(openReq.result, false); + uv_fs_req_cleanup(&openReq); + } + return InstantiateRandomAccessFile(env, fileInfo.fdg.GetFD(), fp).val_; +} + +struct AsyncCreateRandomAccessFileArg { + int fd; + size_t fp; +}; + +napi_value CreateRandomAccessFile::Async(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::FOUR)) { + UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched"); + return nullptr; + } + auto [succ, fileInfo, fp] = ParseJsFileAndFP(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + return nullptr; + } + auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo); + if (!succFlags) { + return nullptr; + } + auto arg = make_shared(); + auto cbExec = [arg, fileInfo = make_shared(move(fileInfo)), fp = fp, flags = + flags](napi_env env) -> UniError { + if (fileInfo->isPath) { + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(env, &loop); + uv_fs_t openReq; + int ret = uv_fs_open(loop, &openReq, fileInfo->path.get(), flags, S_IRUSR | + S_IWUSR | S_IRGRP | S_IWGRP, NULL); + if (ret < 0) { + return UniError(errno); + } + fileInfo->fdg.SetFD(openReq.result, false); + uv_fs_req_cleanup(&openReq); + } + arg->fd = fileInfo->fdg.GetFD(); + arg->fp = fp; + return UniError(ERRNO_NOERR); + }; + auto cbCompl = [arg](napi_env env, UniError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return InstantiateRandomAccessFile(env, arg->fd, arg->fp); + }; + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::TWO || (funcArg.GetArgc() == NARG_CNT::THREE && + NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number))) { + return NAsyncWorkPromise(env, thisVar).Schedule(createRAFProcedureName, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::FOUR) ? NARG_POS::FOURTH : NARG_POS::THIRD); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(createRAFProcedureName, cbExec, cbCompl).val_; + } +} +} // namespace ModuleFileIO +} // namespace DistributedFS +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.h b/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.h index f4a9b36bad948ea71a3070f7da973396fa6ff6b7..afde2e387c248c7f736f836c45b38fd8d18bdef4 100644 --- a/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.h +++ b/interfaces/kits/js/src/mod_fileio/properties/create_randomaccessfile.h @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_PROPERTIES_CREATE_RANDOMACCESSFILE_H -#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_PROPERTIES_CREATE_RANDOMACCESSFILE_H - -#include "../../common/napi/uni_header.h" - -namespace OHOS { -namespace DistributedFS { -namespace ModuleFileIO { -class CreateRandomAccessFile final { -public: - static napi_value Async(napi_env env, napi_callback_info info); - static napi_value Sync(napi_env env, napi_callback_info info); -}; -const std::string createRAFProcedureName = "FileIOCreateRandomAccessFile"; -} // namespace ModuleFileIO -} // namespace DistributedFS -} // namespace OHOS -#endif \ No newline at end of file +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FILEIO_PROPERTIES_CREATE_RANDOMACCESSFILE_H +#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_PROPERTIES_CREATE_RANDOMACCESSFILE_H + +#include "../../common/napi/uni_header.h" + +namespace OHOS { +namespace DistributedFS { +namespace ModuleFileIO { +class CreateRandomAccessFile final { +public: + static napi_value Async(napi_env env, napi_callback_info info); + static napi_value Sync(napi_env env, napi_callback_info info); +}; +const std::string createRAFProcedureName = "FileIOCreateRandomAccessFile"; +} // namespace ModuleFileIO +} // namespace DistributedFS +} // namespace OHOS +#endif diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_entity.h b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_entity.h new file mode 100644 index 0000000000000000000000000000000000000000..be447791fab85e3759c4a8340665f5b58534468c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_entity.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H + +#include + +#include "fd_guard.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +struct RandomAccessFileEntity { + std::unique_ptr fd = { nullptr }; + int64_t filePointer = 0; +}; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e7a3766e002e39872f83eec1338918da50d1dbdc --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.cpp @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "randomaccessfile_n_exporter.h" + +#include "file_utils.h" +#include "randomaccessfile_entity.h" +#include "../common_func.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::FileManagement::LibN; + +static tuple GetRAFEntity(napi_env env, napi_value raf_entity) +{ + auto rafEntity = NClass::GetEntityOf(env, raf_entity); + if (!rafEntity) { + return { false, nullptr }; + } + return { true, rafEntity }; +} + +static int DoReadRAF(napi_env env, void* buf, size_t len, int fd, int64_t offset) +{ + std::unique_ptr read_req = { + new (nothrow) uv_fs_t, CommonFunc::fs_req_cleanup }; + if (read_req == nullptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + uv_buf_t iov = uv_buf_init(static_cast(buf), len); + int ret = uv_fs_read(nullptr, read_req.get(), fd, &iov, 1, offset, nullptr); + return ret; +} + +static int DoWriteRAF(napi_env env, void* buf, size_t len, int fd, int64_t offset) +{ + std::unique_ptr write_req = { + new (nothrow) uv_fs_t, CommonFunc::fs_req_cleanup }; + if (write_req == nullptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + uv_buf_t iov = uv_buf_init(static_cast(buf), len); + int ret = uv_fs_write(nullptr, write_req.get(), fd, &iov, 1, offset, nullptr); + return ret; +} + +napi_value RandomAccessFileNExporter::GetFD(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return NVal::CreateInt32(env, rafEntity->fd.get()->GetFD()).val_; +} + +napi_value RandomAccessFileNExporter::GetFPointer(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return NVal::CreateInt64(env, rafEntity->filePointer).val_; +} + +napi_value RandomAccessFileNExporter::SetFilePointerSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + auto [succ, fp] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt64(); + if (!succ) { + HILOGE("Invalid filePointer"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + rafEntity->filePointer = fp; + return NVal::CreateUndefined(env).val_; +} + +static int64_t CalculateOffset(int64_t offset, int64_t fPointer) +{ + if (offset < 0) { + HILOGI("No specified offset provided"); + offset = fPointer; + } else { + offset += fPointer; + } + return offset; +} + +napi_value RandomAccessFileNExporter::ReadSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + auto [succ, buf, len, offset] = + CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Invalid buffer/options"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + offset = CalculateOffset(offset, rafEntity->filePointer); + int actLen = DoReadRAF(env, buf, len, rafEntity->fd.get()->GetFD(), offset); + if (actLen < 0) { + HILOGE("Failed to read file for %{public}d", actLen); + NError(actLen).ThrowErr(env); + return nullptr; + } + rafEntity->filePointer = offset + actLen; + return NVal::CreateInt64(env, actLen).val_; +} + +struct AsyncIORafReadArg { + int lenRead { 0 }; + NRef rafRefReadBuf; + + explicit AsyncIORafReadArg(NVal jsReadBuf) : rafRefReadBuf(jsReadBuf) {} + ~AsyncIORafReadArg() = default; +}; + +static napi_value ReadExec(napi_env env, NFuncArg &funcArg, RandomAccessFileEntity* rafEntity) +{ + bool succ = false; + void *buf = nullptr; + size_t len = 0; + int64_t offset = 0; + tie(succ, buf, len, offset) = CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Invalid buffer/options"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto arg = CreateSharedPtr(NVal(env, funcArg[NARG_POS::FIRST])); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + offset = CalculateOffset(offset, rafEntity->filePointer); + auto cbExec = [env, arg, buf, len, offset, rafEntity]() -> NError { + int actLen = DoReadRAF(env, buf, len, rafEntity->fd.get()->GetFD(), offset); + if (actLen < 0) { + return NError(actLen); + } + arg->lenRead = actLen; + rafEntity->filePointer = offset + actLen; + return NError(ERRNO_NOERR); + }; + auto cbCompl = [arg](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return { NVal::CreateInt64(env, static_cast(arg->lenRead)) }; + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && + !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) { + return NAsyncWorkPromise(env, thisVar).Schedule(readProcedureName, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(readProcedureName, cbExec, cbCompl).val_; + } +} + +napi_value RandomAccessFileNExporter::Read(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto[succ, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succ) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return ReadExec(env, funcArg, rafEntity); +} + +napi_value RandomAccessFileNExporter::WriteSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + auto [succ, ignore, buf, len, offset] = + CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Invalid buffer/options"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + offset = CalculateOffset(offset, rafEntity->filePointer); + int writeLen = DoWriteRAF(env, buf, len, rafEntity->fd.get()->GetFD(), offset); + if (writeLen < 0) { + NError(writeLen).ThrowErr(env); + return nullptr; + } + rafEntity->filePointer = offset + writeLen; + return NVal::CreateInt64(env, writeLen).val_; +} + +struct AsyncIORafWriteArg { + NRef rafRefWriteArrayBuf; + size_t actLen = 0; + explicit AsyncIORafWriteArg(NVal refWriteArrayBuf) : rafRefWriteArrayBuf(refWriteArrayBuf) {} + ~AsyncIORafWriteArg() = default; +}; + +static napi_value WriteExec(napi_env env, NFuncArg &funcArg, RandomAccessFileEntity* rafEntity) +{ + bool succ = false; + void *buf = nullptr; + size_t len = 0; + int64_t offset = 0; + tie(succ, ignore, buf, len, offset) = + CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Invalid buffer/options"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto arg = CreateSharedPtr(NVal(env, funcArg[NARG_POS::FIRST])); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + offset = CalculateOffset(offset, rafEntity->filePointer); + auto cbExec = [env, arg, buf, len, fd = rafEntity->fd.get()->GetFD(), offset, rafEntity]() -> NError { + int writeLen = DoWriteRAF(env, buf, len, fd, offset); + if (writeLen < 0) { + HILOGE("Failed to write file for %{public}d", writeLen); + return NError(writeLen); + } + arg->actLen = writeLen; + rafEntity->filePointer = offset + writeLen; + return NError(ERRNO_NOERR); + }; + + auto cbCompl = [arg](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return { NVal::CreateInt64(env, arg->actLen) }; + } + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && + !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function))) { + return NAsyncWorkPromise(env, thisVar).Schedule(writeProcedureName, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(writeProcedureName, cbExec, cbCompl).val_; + } +} + +napi_value RandomAccessFileNExporter::Write(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto[succ, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succ) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return WriteExec(env, funcArg, rafEntity); +} + +static NError CloseFd(int fd) +{ + std::unique_ptr close_req = { + new uv_fs_t, CommonFunc::fs_req_cleanup }; + if (!close_req) { + HILOGE("Failed to request heap memory."); + return NError(ENOMEM); + } + int ret = uv_fs_close(nullptr, close_req.get(), fd, nullptr); + if (ret < 0) { + HILOGE("Failed to close file with ret: %{public}d", ret); + return NError(ret); + } + return NError(ERRNO_NOERR); +} + +napi_value RandomAccessFileNExporter::CloseSync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succEntity, rafEntity] = GetRAFEntity(env, funcArg.GetThisVar()); + if (!succEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + auto err = CloseFd(rafEntity->fd.get()->GetFD()); + if (err) { + err.ThrowErr(env); + return nullptr; + } + auto fp = NClass::RemoveEntityOfFinal(env, funcArg.GetThisVar()); + if (!fp) { + HILOGE("Failed to remove entity of RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return NVal::CreateUndefined(env).val_; +} + +napi_value RandomAccessFileNExporter::Constructor(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto rafEntity = CreateUniquePtr(); + if (rafEntity == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(rafEntity))) { + HILOGE("INNER BUG. Failed to wrap entity for obj RandomAccessFile"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return funcArg.GetThisVar(); +} + +bool RandomAccessFileNExporter::Export() +{ + vector props = { + NVal::DeclareNapiFunction("read", Read), + NVal::DeclareNapiFunction("readSync", ReadSync), + NVal::DeclareNapiFunction("write", Write), + NVal::DeclareNapiFunction("writeSync", WriteSync), + NVal::DeclareNapiFunction("setFilePointer", SetFilePointerSync), + NVal::DeclareNapiFunction("close", CloseSync), + NVal::DeclareNapiGetter("fd", GetFD), + NVal::DeclareNapiGetter("filePointer", GetFPointer), + }; + + string className = GetClassName(); + bool succ = false; + napi_value classValue = nullptr; + tie(succ, classValue) = NClass::DefineClass(exports_.env_, className, + RandomAccessFileNExporter::Constructor, move(props)); + if (!succ) { + HILOGE("INNER BUG. Failed to define class"); + NError(EIO).ThrowErr(exports_.env_); + return false; + } + succ = NClass::SaveClass(exports_.env_, className, classValue); + if (!succ) { + HILOGE("INNER BUG. Failed to define class"); + NError(EIO).ThrowErr(exports_.env_); + return false; + } + + return exports_.AddProp(className, classValue); +} + +string RandomAccessFileNExporter::GetClassName() +{ + return RandomAccessFileNExporter::className_; +} + +RandomAccessFileNExporter::RandomAccessFileNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {} + +RandomAccessFileNExporter::~RandomAccessFileNExporter() {} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.h b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.h new file mode 100644 index 0000000000000000000000000000000000000000..9d42aa87e122d440000c4d89d2b63d3c78547250 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_N_EXPORTER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_N_EXPORTER_H + +#include "filemgmt_libhilog.h" +#include "filemgmt_libn.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace OHOS::FileManagement::LibN; + +class RandomAccessFileNExporter final : public NExporter { +public: + inline static const std::string className_ = "RandomAccessFile"; + + bool Export() override; + std::string GetClassName() override; + + static napi_value Constructor(napi_env env, napi_callback_info cbinfo); + + static napi_value SetFilePointerSync(napi_env env, napi_callback_info cbinfo); + static napi_value WriteSync(napi_env env, napi_callback_info cbinfo); + static napi_value ReadSync(napi_env env, napi_callback_info cbinfo); + static napi_value CloseSync(napi_env env, napi_callback_info cbinfo); + + static napi_value Write(napi_env env, napi_callback_info cbinfo); + static napi_value Read(napi_env env, napi_callback_info cbinfo); + + static napi_value GetFD(napi_env env, napi_callback_info cbinfo); + static napi_value GetFPointer(napi_env env, napi_callback_info cbinfo); + + RandomAccessFileNExporter(napi_env env, napi_value exports); + ~RandomAccessFileNExporter() override; +}; +const std::string readProcedureName = "FileIORandomAccessFileRead"; +const std::string writeProcedureName = "FileIORandomAccessFileWrite"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/module.cpp b/interfaces/kits/js/src/mod_fs/module.cpp index e0a73f74d544aff35d889dc7d6c28ef24c6fef7e..785d066cbfa05fe856a3ed98af7365dff3c1be4b 100644 --- a/interfaces/kits/js/src/mod_fs/module.cpp +++ b/interfaces/kits/js/src/mod_fs/module.cpp @@ -19,6 +19,7 @@ #include #include "class_file/file_n_exporter.h" +#include "class_randomaccessfile/randomaccessfile_n_exporter.h" #include "class_stat/stat_n_exporter.h" #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) #include "class_stream/stream_n_exporter.h" @@ -38,6 +39,7 @@ static napi_value Export(napi_env env, napi_value exports) std::vector> products; products.emplace_back(make_unique(env, exports)); products.emplace_back(make_unique(env, exports)); + products.emplace_back(make_unique(env, exports)); products.emplace_back(make_unique(env, exports)); #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) products.emplace_back(make_unique(env, exports)); diff --git a/interfaces/kits/js/src/mod_fs/properties/close.cpp b/interfaces/kits/js/src/mod_fs/properties/close.cpp index 0080d78c91c128c2793eea3dd6f08e828cfe6a7f..0ca2fe8e5ffc57ff0b3f53cc72717c7e13d01c8a 100755 --- a/interfaces/kits/js/src/mod_fs/properties/close.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/close.cpp @@ -36,7 +36,7 @@ static FileEntity *GetFileEntity(napi_env env, napi_value objFile) return nullptr; } if (!fileEntity->fd_) { - HILOGE("The fd of rafEntity is not exist"); + HILOGE("The fd of entity is not exist"); return nullptr; } return fileEntity; diff --git a/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.cpp b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..845fcf8891ff4c76fca9d3dfd1af53f29934be92 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "create_randomaccessfile.h" + +#include "class_file/file_entity.h" +#include "class_randomaccessfile/randomaccessfile_entity.h" +#include "class_randomaccessfile/randomaccessfile_n_exporter.h" +#include "common_func.h" +#include "file_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::FileManagement::LibN; + +static FileEntity* GetFileEntity(napi_env env, napi_value objFile) +{ + auto fileEntity = NClass::GetEntityOf(env, objFile); + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return nullptr; + } + if (!fileEntity->fd_) { + HILOGE("The fd of entity is not exist"); + return nullptr; + } + return fileEntity; +} + +static tuple ParseJsFile(napi_env env, napi_value pathOrFileFromJsArg) +{ + auto [isPath, path, ignore] = NVal(env, pathOrFileFromJsArg).ToUTF8String(); + if (isPath) { + OHOS::DistributedFS::FDGuard sfd; + auto fdg = CreateUniquePtr(sfd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + return { false, FileInfo { false, nullptr, nullptr }, ENOMEM}; + } + return { true, FileInfo { true, move(path), move(fdg) }, ERRNO_NOERR}; + } + auto fileEntity = GetFileEntity(env, pathOrFileFromJsArg); + if (fileEntity) { + auto fd = fileEntity->fd_.get()->GetFD(); + if (fd < 0) { + HILOGE("Invalid fd"); + return { false, FileInfo { false, nullptr, nullptr }, EINVAL}; + } + auto dupFd = dup(fd); + if (dupFd < 0) { + HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd); + return { false, FileInfo { false, nullptr, nullptr }, EINVAL}; + } + auto fdg = CreateUniquePtr(dupFd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + return { false, FileInfo { false, nullptr, nullptr }, ENOMEM}; + } + return { true, FileInfo { false, nullptr, move(fdg) }, ERRNO_NOERR}; + } + HILOGE("The first argument requires filepath/file"); + return { false, FileInfo { false, nullptr, nullptr }, EINVAL}; +} + +static tuple GetJsFlags(napi_env env, const NFuncArg &funcArg, FileInfo &fileInfo) +{ + unsigned int flags = O_RDONLY; + if (fileInfo.isPath) { + if (funcArg.GetArgc() >= NARG_CNT::TWO) { + auto [succ, mode] = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32(0); + if (!succ || mode < 0) { + HILOGE("Invalid flags"); + NError(EINVAL).ThrowErr(env); + return { false, flags }; + } + flags = static_cast(mode); + (void)CommonFunc::ConvertJsFlags(flags); + } + } + return { true, flags }; +} + +static NVal InstantiateRandomAccessFile(napi_env env, std::unique_ptr fdg, size_t fp) +{ + napi_value objRAF = NClass::InstantiateClass(env, RandomAccessFileNExporter::className_, {}); + if (!objRAF) { + HILOGE("Cannot instantiate randomaccessfile"); + NError(EIO).ThrowErr(env); + return NVal(); + } + auto rafEntity = NClass::GetEntityOf(env, objRAF); + if (!rafEntity) { + HILOGE("Cannot instantiate randomaccessfile because of void entity"); + NError(EIO).ThrowErr(env); + return NVal(); + } + rafEntity->fd.swap(fdg); + rafEntity->filePointer = fp; + return { env, objRAF }; +} + +napi_value CreateRandomAccessFile::Sync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succ, fileInfo, err] = ParseJsFile(env, funcArg[NARG_POS::FIRST]); + if (!succ) { + NError(err).ThrowErr(env); + return nullptr; + } + if (fileInfo.isPath) { + auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo); + if (!succFlags) { + return nullptr; + } + std::unique_ptr open_req = { + new uv_fs_t, CommonFunc::fs_req_cleanup }; + if (!open_req) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + int ret = uv_fs_open(nullptr, open_req.get(), fileInfo.path.get(), flags, S_IRUSR | + S_IWUSR | S_IRGRP | S_IWGRP, NULL); + if (ret < 0) { + NError(ret).ThrowErr(env); + return nullptr; + } + + fileInfo.fdg->SetFD(open_req.get()->result, false); + } + return InstantiateRandomAccessFile(env, move(fileInfo.fdg), 0).val_; +} + +struct AsyncCreateRandomAccessFileArg { + int fd = 0; + int64_t fp = 0; +}; + +NError AsyncExec(shared_ptr arg, + shared_ptr fileInfo, size_t fp, unsigned int flags) +{ + if (fileInfo->isPath) { + std::unique_ptr open_req = { + new uv_fs_t, CommonFunc::fs_req_cleanup }; + int ret = uv_fs_open(nullptr, open_req.get(), fileInfo->path.get(), flags, S_IRUSR | + S_IWUSR | S_IRGRP | S_IWGRP, NULL); + if (ret < 0) { + return NError(ret); + } + fileInfo->fdg->SetFD(open_req.get()->result, false); + } + arg->fd = fileInfo->fdg->GetFD(); + arg->fp = fp; + return NError(ERRNO_NOERR); +} + +napi_value CreateRandomAccessFile::Async(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + auto [succ, fileInfo, err] = ParseJsFile(env, funcArg[NARG_POS::FIRST]); + if (!succ) { + NError(err).ThrowErr(env); + return nullptr; + } + auto [succFlags, flags] = GetJsFlags(env, funcArg, fileInfo); + if (!succFlags) { + return nullptr; + } + auto arg = CreateSharedPtr(); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + auto movedFileInfo = CreateSharedPtr(move(fileInfo)); + if (movedFileInfo == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + auto cbExec = [arg, movedFileInfo, flags = flags]() -> NError { + return AsyncExec(arg, movedFileInfo, 0, flags); + }; + + auto cbCompl = [arg, movedFileInfo](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return InstantiateRandomAccessFile(env, move(movedFileInfo->fdg), arg->fp); + }; + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && + NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number))) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_CREATERAT_NAME, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::THIRD); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_CREATERAT_NAME, cbExec, cbCompl).val_; + } +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.h b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.h new file mode 100644 index 0000000000000000000000000000000000000000..9ccec6d65e83c5e1deb6f58cf6ea77cb6ee4f198 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_RANDOMACCESSFILE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_RANDOMACCESSFILE_H + +#include "filemgmt_libn.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class CreateRandomAccessFile final { +public: + static napi_value Async(napi_env env, napi_callback_info info); + static napi_value Sync(napi_env env, napi_callback_info info); +}; +const std::string PROCEDURE_CREATERAT_NAME = "FileIOCreateRandomAccessFile"; +} // namespace ModuleFileIO +} // namespace DistributedFS +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/prop_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/properties/prop_n_exporter.cpp index 6b705dc8439ae37ca7e98e80266d9aa3a9ab95be..f2f2de072dd04d987e26af7b62386462102acc62 100644 --- a/interfaces/kits/js/src/mod_fs/properties/prop_n_exporter.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/prop_n_exporter.cpp @@ -43,6 +43,7 @@ #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) #include "copy_file.h" #include "copydir.h" +#include "create_randomaccessfile.h" #include "create_stream.h" #include "fdopen_stream.h" #include "listfile.h" @@ -592,6 +593,8 @@ bool PropNExporter::Export() NVal::DeclareNapiFunction("copyDirSync", CopyDir::Sync), NVal::DeclareNapiFunction("copyFile", CopyFile::Async), NVal::DeclareNapiFunction("copyFileSync", CopyFile::Sync), + NVal::DeclareNapiFunction("createRandomAccessFile", CreateRandomAccessFile::Async), + NVal::DeclareNapiFunction("createRandomAccessFileSync", CreateRandomAccessFile::Sync), NVal::DeclareNapiFunction("createStream", CreateStream::Async), NVal::DeclareNapiFunction("createStreamSync", CreateStream::Sync), NVal::DeclareNapiFunction("fdopenStream", FdopenStream::Async),