From b86b9b780a7a29a2f26e4230049d5dcd5966d842 Mon Sep 17 00:00:00 2001 From: futurezhou Date: Fri, 6 Jan 2023 14:12:05 +0800 Subject: [PATCH] Add create_stream and fdopen_stream interface for mod_fs Signed-off-by: futurezhou --- .../kits/js/src/mod_fs/class_stream/flush.cpp | 98 +++++ .../kits/js/src/mod_fs/class_stream/flush.h | 34 ++ .../src/mod_fs/class_stream/stream_entity.h | 29 ++ .../mod_fs/class_stream/stream_n_exporter.cpp | 389 ++++++++++++++++++ .../mod_fs/class_stream/stream_n_exporter.h | 70 ++++ .../src/mod_fs/properties/create_stream.cpp | 139 +++++++ .../js/src/mod_fs/properties/create_stream.h | 38 ++ .../src/mod_fs/properties/fdopen_stream.cpp | 139 +++++++ .../js/src/mod_fs/properties/fdopen_stream.h | 38 ++ 9 files changed, 974 insertions(+) create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/flush.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/flush.h create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/stream_entity.h create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp create mode 100644 interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.h create mode 100755 interfaces/kits/js/src/mod_fs/properties/create_stream.cpp create mode 100755 interfaces/kits/js/src/mod_fs/properties/create_stream.h create mode 100755 interfaces/kits/js/src/mod_fs/properties/fdopen_stream.cpp create mode 100755 interfaces/kits/js/src/mod_fs/properties/fdopen_stream.h diff --git a/interfaces/kits/js/src/mod_fs/class_stream/flush.cpp b/interfaces/kits/js/src/mod_fs/class_stream/flush.cpp new file mode 100644 index 000000000..6d21dd570 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/flush.cpp @@ -0,0 +1,98 @@ +/* + * 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 "flush.h" + +#include +#include + +#include "class_stat/stat_entity.h" +#include "class_stat/stat_n_exporter.h" +#include "filemgmt_libhilog.h" +#include "stream_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::FileManagement::LibN; + +napi_value Flush::Sync(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 streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may has been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + + int ret = fflush(streamEntity->fp.get()); + if (ret < 0) { + HILOGE("Failed to fflush file in the stream, ret: %{public}d", ret); + NError(errno).ThrowErr(env); + return nullptr; + } + return NVal::CreateUndefined(env).val_; +} + +napi_value Flush::Async(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may has been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + + auto cbExec = [streamEntity]() -> NError { + int ret = fflush(streamEntity->fp.get()); + if (ret < 0) { + HILOGE("Failed to fflush file in the stream"); + return NError(errno); + } else { + return NError(ERRNO_NOERR); + } + }; + auto cbCompl = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return { NVal::CreateUndefined(env) }; + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ZERO) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_FLUSH_NAME, cbExec, cbCompl).val_; + } else { + NVal cb(env, funcArg[NARG_POS::FIRST]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_STREAM_FLUSH_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/class_stream/flush.h b/interfaces/kits/js/src/mod_fs/class_stream/flush.h new file mode 100644 index 000000000..aa7be7012 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/flush.h @@ -0,0 +1,34 @@ +/* + * 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_STREAM_FLUSH_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_FLUSH_H + +#include "filemgmt_libn.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class Flush 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_STREAM_FLUSH_NAME = "FileIOStreamFlush"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_FLUSH_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_entity.h b/interfaces/kits/js/src/mod_fs/class_stream/stream_entity.h new file mode 100644 index 000000000..11cdae1dc --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_entity.h @@ -0,0 +1,29 @@ +/* + * 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_FILEIO_CLASS_STREAM_STREAM_ENTITY_H +#define INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_STREAM_STREAM_ENTITY_H + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +struct StreamEntity { + std::unique_ptr fp = { nullptr, fclose }; +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FILEIO_CLASS_STREAM_STREAM_ENTITY_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp new file mode 100644 index 000000000..2cc0aedb8 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.cpp @@ -0,0 +1,389 @@ +/* + * 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 "stream_n_exporter.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common_func.h" +#include "filemgmt_libhilog.h" +#include "flush.h" +#include "stream_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::FileManagement::LibN; + +napi_value StreamNExporter::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 streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may have been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + FILE *filp = nullptr; + filp = streamEntity->fp.get(); + + auto [succ, buf, len, hasOffset, offset] = + CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Failed to resolve buf and options"); + return nullptr; + } + + int ret = fseek(filp, offset, SEEK_SET); + if (hasOffset && (ret < 0)) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + NError(errno).ThrowErr(env); + return nullptr; + } + + size_t actLen = fread(buf, 1, len, filp); + if (actLen != static_cast(len) && ferror(filp)) { + HILOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen); + NError(errno).ThrowErr(env); + return nullptr; + } + + return NVal::CreateInt64(env, actLen).val_; +} + +napi_value StreamNExporter::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 streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may have been closed yet"); + NError(EIO).ThrowErr(env); + return nullptr; + } + streamEntity->fp.reset(); + + return NVal::CreateUndefined(env).val_; +} + +napi_value StreamNExporter::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 streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may has been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + FILE *filp = nullptr; + filp = streamEntity->fp.get(); + + auto [succ, bufGuard, buf, len, hasOffset, offset] = + CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Failed to resolve buf and options"); + return nullptr; + } + int ret = fseek(filp, offset, SEEK_SET); + if (hasOffset && (ret < 0)) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + NError(errno).ThrowErr(env); + return nullptr; + } + + size_t writeLen = fwrite(buf, 1, len, filp); + if (writeLen != len && ferror(filp)) { + HILOGE("Failed to fwrite with len, writeLen: %{public}zu, len: %{public}" PRId64, writeLen, len); + NError(errno).ThrowErr(env); + return nullptr; + } + + return NVal::CreateInt64(env, writeLen).val_; +} + +static bool HasOption(napi_env env, napi_value optionFromJsArg) +{ + NVal op = NVal(env, optionFromJsArg); + if (op.HasProp("offset") || op.HasProp("length") || op.HasProp("encoding") || !op.TypeIs(napi_function)) { + return true; + } + return false; +} + +napi_value StreamNExporter::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 streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may has been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + + FILE *filp = nullptr; + filp = streamEntity->fp.get(); + + auto [succ, bufGuard, buf, len, hasOffset, offset] = + CommonFunc::GetWriteArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Failed to resolve buf and options"); + return nullptr; + } + + auto arg = make_shared(move(bufGuard)); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + auto cbExec = [arg, buf = buf, len = len, filp, hasOffset = hasOffset, offset = offset]() -> NError { + int ret = fseek(filp, offset, SEEK_SET); + if (hasOffset && (ret < 0)) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return NError(errno); + } + arg->actLen = fwrite(buf, 1, len, filp); + if ((arg->actLen != static_cast(len)) && ferror(filp)) { + HILOGE("Invalid buffer size and pointer, actlen: %{public}zu", arg->actLen); + return NError(errno); + } + return NError(ERRNO_NOERR); + }; + + auto cbCompl = [arg](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return { NVal::CreateInt64(env, arg->actLen) }; + }; + + NVal thisVar(env, funcArg.GetThisVar()); + bool hasOp = false; + if (funcArg.GetArgc() == NARG_CNT::TWO) { + hasOp = HasOption(env, funcArg[NARG_POS::SECOND]); + } + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && hasOp)) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_WRITE_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_STREAM_WRITE_NAME, cbExec, cbCompl).val_; + } +} + +napi_value StreamNExporter::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 streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may have been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + FILE *filp = nullptr; + filp = streamEntity->fp.get(); + + auto [succ, buf, len, hasOffset, offset] = + CommonFunc::GetReadArg(env, funcArg[NARG_POS::FIRST], funcArg[NARG_POS::SECOND]); + if (!succ) { + HILOGE("Failed to resolve buf and options"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto arg = make_shared(NVal(env, funcArg[NARG_POS::FIRST])); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + auto cbExec = [arg, buf = buf, len = len, filp, hasOffset = hasOffset, offset = offset]() -> NError { + int ret = fseek(filp, offset, SEEK_SET); + if (hasOffset && (ret < 0)) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return NError(errno); + } + size_t actLen = fread(buf, 1, len, filp); + if (actLen != static_cast(len) && ferror(filp)) { + HILOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen); + return NError(errno); + } else { + arg->lenRead = 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, arg->lenRead) }; + }; + + NVal thisVar(env, funcArg.GetThisVar()); + bool hasOp = false; + if (funcArg.GetArgc() == NARG_CNT::TWO) { + hasOp = HasOption(env, funcArg[NARG_POS::SECOND]); + } + if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO && hasOp)) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_READ_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_STREAM_READ_NAME, cbExec, cbCompl).val_; + } +} + +napi_value StreamNExporter::Close(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto streamEntity = NClass::GetEntityOf(env, funcArg.GetThisVar()); + if (!streamEntity || !streamEntity->fp) { + HILOGE("Stream may has been closed"); + NError(EIO).ThrowErr(env); + return nullptr; + } + + auto cbExec = [streamEntity]() -> NError { + auto filp = streamEntity->fp.release(); + if (!fclose(filp)) { + HILOGE("Failed to close file with filp"); + return NError(ERRNO_NOERR); + } else { + return NError(errno); + } + }; + + auto cbCompl = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } else { + return NVal::CreateUndefined(env); + } + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ZERO) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_STREAM_CLOSE_NAME, cbExec, cbCompl).val_; + } else { + NVal cb(env, funcArg[NARG_POS::FIRST]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_STREAM_CLOSE_NAME, cbExec, cbCompl).val_; + } +} + +napi_value StreamNExporter::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; + } + + unique_ptr streamEntity = make_unique(); + if (!NClass::SetEntityFor(env, funcArg.GetThisVar(), move(streamEntity))) { + HILOGE("INNER BUG. Failed to wrap entity for obj stream"); + NError(EIO).ThrowErr(env); + return nullptr; + } + return funcArg.GetThisVar(); +} + +bool StreamNExporter::Export() +{ + vector props = { + NVal::DeclareNapiFunction("writeSync", WriteSync), + NVal::DeclareNapiFunction("flush", Flush::Async), + NVal::DeclareNapiFunction("flushSync", Flush::Sync), + NVal::DeclareNapiFunction("readSync", ReadSync), + NVal::DeclareNapiFunction("closeSync", CloseSync), + NVal::DeclareNapiFunction("write", Write), + NVal::DeclareNapiFunction("read", Read), + NVal::DeclareNapiFunction("close", Close), + }; + + string className = GetClassName(); + bool succ = false; + napi_value cls = nullptr; + tie(succ, cls) = NClass::DefineClass(exports_.env_, className, StreamNExporter::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, cls); + if (!succ) { + HILOGE("INNER BUG. Failed to save class"); + NError(EIO).ThrowErr(exports_.env_); + return false; + } + + return exports_.AddProp(className, cls); +} + +string StreamNExporter::GetClassName() +{ + return StreamNExporter::className_; +} + +StreamNExporter::StreamNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {} + +StreamNExporter::~StreamNExporter() {} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.h b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.h new file mode 100644 index 000000000..afb2579e6 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_n_exporter.h @@ -0,0 +1,70 @@ +/* + * 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_STREAM_STREAM_N_EXPORTER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_STREAM_N_EXPORTER_H + +#include "filemgmt_libn.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace OHOS::FileManagement::LibN; +class StreamNExporter final : public NExporter { +public: + inline static const std::string className_ = "FsStream"; + + bool Export() override; + std::string GetClassName() override; + + static napi_value Constructor(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 Close(napi_env env, napi_callback_info cbinfo); + + StreamNExporter(napi_env env, napi_value exports); + ~StreamNExporter() override; +}; + +struct AsyncReadArg { + size_t lenRead { 0 }; + NRef refReadBuf; + + explicit AsyncReadArg(NVal jsReadBuf) : refReadBuf(jsReadBuf) {} + ~AsyncReadArg() = default; +}; + +struct AsyncWrtieArg { + NRef refWriteArrayBuf; + std::unique_ptr guardWriteStr; + size_t actLen { 0 }; + + explicit AsyncWrtieArg(NVal refWriteArrayBuf) : refWriteArrayBuf(refWriteArrayBuf) {} + explicit AsyncWrtieArg(std::unique_ptr &&guardWriteStr) : guardWriteStr(std::move(guardWriteStr)) {} + ~AsyncWrtieArg() = default; +}; + +const std::string PROCEDURE_STREAM_WRITE_NAME = "FileIOStreamWrite"; +const std::string PROCEDURE_STREAM_READ_NAME = "FileIOStreamRead"; +const std::string PROCEDURE_STREAM_CLOSE_NAME = "FileIOStreamClose"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_STREAM_N_EXPORTER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/create_stream.cpp b/interfaces/kits/js/src/mod_fs/properties/create_stream.cpp new file mode 100755 index 000000000..e63178df2 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_stream.cpp @@ -0,0 +1,139 @@ +/* + * 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_stream.h" + +#include +#include + +#include "class_stream/stream_entity.h" +#include "class_stream/stream_n_exporter.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::FileManagement::LibN; + +static NVal InstantiateStream(napi_env env, unique_ptr fp) +{ + napi_value objStream = NClass::InstantiateClass(env, StreamNExporter::className_, {}); + if (!objStream) { + HILOGE("INNER BUG. Cannot instantiate stream"); + NError(EIO).ThrowErr(env); + return NVal(); + } + + auto streamEntity = NClass::GetEntityOf(env, objStream); + if (!streamEntity) { + HILOGE("Cannot instantiate stream because of void entity"); + NError(EIO).ThrowErr(env); + return NVal(); + } + + streamEntity->fp.swap(fp); + return { env, objStream }; +} + +static tuple GetCreateStreamArgs(napi_env env, const NFuncArg &funcArg) +{ + auto [resGetFirstArg, path, unused] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); + if (!resGetFirstArg) { + return { false, "", "" }; + } + + auto [resGetSecondArg, mode, useless] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String(); + if (!resGetSecondArg) { + return { false, "", "" }; + } + + return { true, path.get(), mode.get() }; +} + +napi_value CreateStream::Sync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto [resGetCreateStreamArgs, argPath, argMode] = GetCreateStreamArgs(env, funcArg); + if (!resGetCreateStreamArgs) { + HILOGE("Arg path and mode are required to be type of string"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + unique_ptr fp = { fopen(argPath.c_str(), argMode.c_str()), fclose }; + if (!fp) { + HILOGE("Failed to fdopen file by path"); + NError(errno).ThrowErr(env); + return nullptr; + } + + return InstantiateStream(env, move(fp)).val_; +} + +napi_value CreateStream::Async(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto [resGetCreateStreamArgs, argPath, argMode] = GetCreateStreamArgs(env, funcArg); + if (!resGetCreateStreamArgs) { + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto arg = make_shared(); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + auto cbExec = [arg, argPath = move(argPath), argMode = move(argMode)]() -> NError { + arg->fp = { fopen(argPath.c_str(), argMode.c_str()), fclose }; + if (!arg->fp) { + HILOGE("Failed to fdopen file by path"); + return NError(errno); + } + return NError(ERRNO_NOERR); + }; + + auto cbCompl = [arg](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return InstantiateStream(env, move(arg->fp)); + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::TWO) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_CREATESTREAM_NAME, cbExec, cbCompl).val_; + } else { + NVal cb(env, funcArg[NARG_POS::THIRD]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_CREATESTREAM_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_stream.h b/interfaces/kits/js/src/mod_fs/properties/create_stream.h new file mode 100755 index 000000000..9e7b01493 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_stream.h @@ -0,0 +1,38 @@ +/* + * 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_STREAM_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_H + +#include "filemgmt_libn.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class CreateStream final { +public: + static napi_value Async(napi_env env, napi_callback_info info); + static napi_value Sync(napi_env env, napi_callback_info info); +}; + +struct AsyncCreateStreamArg { + std::unique_ptr fp = { nullptr, fclose }; +}; + +const std::string PROCEDURE_CREATESTREAM_NAME = "FileIOCreateStream"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fdopen_stream.cpp b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream.cpp new file mode 100755 index 000000000..2fab9f21a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream.cpp @@ -0,0 +1,139 @@ +/* + * 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 "fdopen_stream.h" + +#include +#include + +#include "class_stream/stream_entity.h" +#include "class_stream/stream_n_exporter.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::FileManagement::LibN; + +static NVal InstantiateStream(napi_env env, unique_ptr fp) +{ + napi_value objStream = NClass::InstantiateClass(env, StreamNExporter::className_, {}); + if (!objStream) { + HILOGE("INNER BUG. Cannot instantiate stream"); + NError(EIO).ThrowErr(env); + return NVal(); + } + + auto streamEntity = NClass::GetEntityOf(env, objStream); + if (!streamEntity) { + HILOGE("Cannot instantiate stream because of void entity"); + NError(EIO).ThrowErr(env); + return NVal(); + } + + streamEntity->fp.swap(fp); + return { env, objStream }; +} + +static tuple GetFdopenStreamArgs(napi_env env, const NFuncArg &funcArg) +{ + auto [resGetFirstArg, fd] = NVal(env, funcArg[NARG_POS::FIRST]).ToInt32(); + if (!resGetFirstArg) { + return { false, -1, "" }; + } + + auto [resGetSecondArg, mode, unused] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String(); + if (!resGetSecondArg) { + return { false, -1, "" }; + } + + return { true, fd, mode.get() }; +} + +napi_value FdopenStream::Sync(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto [resGetFdopenStreamArgs, fd, mode] = GetFdopenStreamArgs(env, funcArg); + if (!resGetFdopenStreamArgs) { + HILOGE("Invalid fd or mode from JS arugments"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + unique_ptr fp = { fdopen(fd, mode.c_str()), fclose }; + if (!fp) { + HILOGE("Failed to fdopen file by fd:%{public}d", fd); + NError(errno).ThrowErr(env); + return nullptr; + } + + return InstantiateStream(env, move(fp)).val_; +} + +napi_value FdopenStream::Async(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto [resGetFdopenStreamArgs, fd, mode] = GetFdopenStreamArgs(env, funcArg); + if (!resGetFdopenStreamArgs) { + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto arg = make_shared(); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + NError(ENOMEM).ThrowErr(env); + return nullptr; + } + auto cbExec = [arg, fd = fd, mode = mode]() -> NError { + arg->fp = { fdopen(fd, mode.c_str()), fclose }; + if (!arg->fp) { + HILOGE("Failed to fdopen file by fd:%{public}d", fd); + return NError(errno); + } + return NError(ERRNO_NOERR); + }; + + auto cbCompl = [arg](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return InstantiateStream(env, move(arg->fp)); + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::TWO) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_FDOPENSTREAM_NAME, cbExec, cbCompl).val_; + } else { + NVal cb(env, funcArg[NARG_POS::THIRD]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_FDOPENSTREAM_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/fdopen_stream.h b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream.h new file mode 100755 index 000000000..ed43f3d3b --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream.h @@ -0,0 +1,38 @@ +/* + * 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_FDOPEN_STREAM_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDOPEN_STREAM_H + +#include "filemgmt_libn.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class FdopenStream final { +public: + static napi_value Async(napi_env env, napi_callback_info info); + static napi_value Sync(napi_env env, napi_callback_info info); +}; + +struct AsyncFdopenStreamArg { + std::unique_ptr fp = { nullptr, fclose }; +}; + +const std::string PROCEDURE_FDOPENSTREAM_NAME = "FileIOFdopenStream"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDOPEN_STREAM_H \ No newline at end of file -- Gitee