diff --git a/interfaces/kits/js/BUILD.gn b/interfaces/kits/js/BUILD.gn index b13c97dba78f5946b8518093e4db6ccd5f967012..cf0a288dfb537b010ac94558ff83f7a415663008 100644 --- a/interfaces/kits/js/BUILD.gn +++ b/interfaces/kits/js/BUILD.gn @@ -148,12 +148,14 @@ ohos_shared_library("fs") { if (!use_mingw_win && !use_mac) { sources += [ + "src/mod_fs/class_randomaccessfile/randomaccessfile_n_exporter.cpp", "src/mod_fs/class_stream/flush.cpp", "src/mod_fs/class_stream/stream_n_exporter.cpp", "src/mod_fs/class_watcher/watcher_entity.cpp", "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_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..a32c4d8fa91cc06c9d9fdb2eface93bb0416c580 --- /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; + int 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..56f8ed6ce39c8f27c79933c143d48d43246d8b55 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile.cpp @@ -0,0 +1,224 @@ +/* + * 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, int64_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; +}; + +NError AsyncExec(shared_ptr arg, + shared_ptr fileInfo, 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(); + 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, flags); + }; + + auto cbCompl = [arg, movedFileInfo](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return InstantiateRandomAccessFile(env, move(movedFileInfo->fdg), 0); + }; + 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..4825fb7fb90a075529e336a4e55c36309c533d2c --- /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 FileManagement +} // 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),