diff --git a/bundle.json b/bundle.json index 78b145b37c41506c2958d7904c596617eca78693..6c5ac79272ef08438e040807365d4fbf540a20a0 100644 --- a/bundle.json +++ b/bundle.json @@ -41,9 +41,12 @@ "ipc", "init", "napi", + "runtime_core", "samgr", "app_file_service", - "os_account" + "os_account", + "openssl", + "libuv" ], "third_party": [ "e2fsprogs", @@ -57,7 +60,8 @@ "//foundation/filemanagement/file_api/interfaces/kits/js:build_kits_js", "//foundation/filemanagement/file_api/interfaces/kits/ts/streamrw:streamrw_packages", "//foundation/filemanagement/file_api/interfaces/kits/ts/streamhash:streamhash_packages", - "//foundation/filemanagement/file_api/interfaces/kits/cj:fs_ffi_packages" + "//foundation/filemanagement/file_api/interfaces/kits/cj:fs_ffi_packages", + "//foundation/filemanagement/file_api/interfaces/kits/js:ani_file_api" ], "service_group": [] }, @@ -98,6 +102,15 @@ "header_base": "//foundation/filemanagement/file_api/interfaces/kits/rust/include" } }, + { + "name": "//foundation/filemanagement/file_api/utils/filemgmt_libfs:filemgmt_libfs", + "header": { + "header_files": [ + "filemgmt_libfs.h" + ], + "header_base": "//foundation/filemanagement/file_api/utils/filemgmt_libfs/include" + } + }, { "name": "//foundation/filemanagement/file_api/utils/filemgmt_libn:filemgmt_libn", "header": { diff --git a/interfaces/kits/js/BUILD.gn b/interfaces/kits/js/BUILD.gn index e06a5ceced045c0612723daad369a7875dd74312..3180ed79692428b20f0210fc75d6b1a4bec380ac 100644 --- a/interfaces/kits/js/BUILD.gn +++ b/interfaces/kits/js/BUILD.gn @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import("//build/config/components/ets_frontend/ets2abc_config.gni") import("//build/ohos.gni") import("//foundation/filemanagement/file_api/file_api.gni") @@ -619,3 +620,353 @@ group("build_kits_js") { ":statvfs", ] } + +group("ani_file_api") { + deps = [ + ":ani_fs_class", + ":ani_hash_class", + ":ani_securitylabel_class", + ":ohos_file_fs_abc", + ] +} + +config("ani_config") { + include_dirs = [ + "./include", + "${file_api_path}/interfaces/kits/rust/include", + "${utils_path}/common/include", + "${utils_path}/filemgmt_libfs/include", + "${utils_path}/filemgmt_libhilog", + "src/common", + "src/common/ani_helper", + "src/common/file_helper", + "src/mod_fs", + ] + + cflags = [ + "-fvisibility=hidden", + "-fdata-sections", + "-ffunction-sections", + "-Oz", + ] + cflags_cc = [ + "-std=c++17", + "-fvisibility-inlines-hidden", + "-Oz", + "-Wno-unused-function", + ] +} + +ohos_shared_library("ani_fs_class") { + public_configs = [ ":ani_config" ] + include_dirs = [ + "include/ipc", + "src/mod_fs/ani", + "src/mod_fs/class_file", + "src/mod_fs/class_file/ani", + "src/mod_fs/class_randomaccessfile", + "src/mod_fs/class_randomaccessfile/ani", + "src/mod_fs/class_readeriterator", + "src/mod_fs/class_readeriterator/ani", + "src/mod_fs/class_stat", + "src/mod_fs/class_stat/ani", + "src/mod_fs/class_stream", + "src/mod_fs/class_stream/ani", + "src/mod_fs/class_tasksignal", + "src/mod_fs/class_tasksignal/ani", + "src/mod_fs/properties", + "src/mod_fs/properties/ani", + "src/mod_fs/properties/copy_listener", + ] + sources = [ + "src/common/ani_helper/error_handler.cpp", + "src/common/ani_helper/type_converter.cpp", + "src/common/file_helper/fd_guard.cpp", + "src/mod_fs/ani/bind_function_class.cpp", + "src/mod_fs/class_file/ani/file_ani.cpp", + "src/mod_fs/class_file/ani/file_wrapper.cpp", + "src/mod_fs/class_file/file_instantiator.cpp", + "src/mod_fs/class_file/fs_file.cpp", + "src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp", + "src/mod_fs/class_randomaccessfile/fs_randomaccessfile.cpp", + "src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp", + "src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp", + "src/mod_fs/class_readeriterator/fs_reader_iterator.cpp", + "src/mod_fs/class_stat/ani/lstat_ani.cpp", + "src/mod_fs/class_stat/ani/stat_ani.cpp", + "src/mod_fs/class_stat/ani/stat_wrapper.cpp", + "src/mod_fs/class_stat/fs_stat.cpp", + "src/mod_fs/class_stream/ani/stream_wrapper.cpp", + "src/mod_fs/class_stream/stream_instantiator.cpp", + "src/mod_fs/class_stream/ani/stream_ani.cpp", + "src/mod_fs/class_stream/fs_stream.cpp", + "src/mod_fs/class_stat/stat_instantiator.cpp", + "src/mod_fs/class_tasksignal/task_signal_entity_core.cpp", + "src/mod_fs/class_tasksignal/ani/task_signal_ani.cpp", + "src/mod_fs/fs_utils.cpp", + "src/mod_fs/properties/access_core.cpp", + "src/mod_fs/properties/ani/access_ani.cpp", + "src/mod_fs/properties/ani/close_ani.cpp", + "src/mod_fs/properties/ani/copy_ani.cpp", + "src/mod_fs/properties/ani/copy_file_ani.cpp", + "src/mod_fs/properties/ani/fsync_ani.cpp", + "src/mod_fs/properties/ani/create_randomaccessfile_ani.cpp", + "src/mod_fs/properties/ani/fdatasync_ani.cpp", + "src/mod_fs/properties/ani/create_stream_ani.cpp", + "src/mod_fs/properties/ani/fdopen_stream_ani.cpp", + "src/mod_fs/properties/ani/dup_ani.cpp", + "src/mod_fs/properties/ani/listfile_ani.cpp", + "src/mod_fs/properties/ani/lseek_ani.cpp", + "src/mod_fs/properties/ani/mkdir_ani.cpp", + "src/mod_fs/properties/ani/mkdtemp_ani.cpp", + "src/mod_fs/properties/ani/move_ani.cpp", + "src/mod_fs/properties/ani/movedir_ani.cpp", + "src/mod_fs/properties/ani/open_ani.cpp", + "src/mod_fs/properties/ani/read_ani.cpp", + "src/mod_fs/properties/ani/read_lines_ani.cpp", + "src/mod_fs/properties/ani/read_text_ani.cpp", + "src/mod_fs/properties/ani/rename_ani.cpp", + "src/mod_fs/properties/ani/rmdir_ani.cpp", + "src/mod_fs/properties/ani/symlink_ani.cpp", + "src/mod_fs/properties/ani/truncate_ani.cpp", + "src/mod_fs/properties/ani/unlink_ani.cpp", + "src/mod_fs/properties/ani/utimes_ani.cpp", + "src/mod_fs/properties/ani/write_ani.cpp", + "src/mod_fs/properties/ani/xattr_ani.cpp", + "src/mod_fs/properties/close_core.cpp", + "src/mod_fs/properties/copy_core.cpp", + "src/mod_fs/properties/copy_file_core.cpp", + "src/mod_fs/properties/fsync_core.cpp", + "src/mod_fs/properties/create_randomaccessfile_core.cpp", + "src/mod_fs/properties/fdatasync_core.cpp", + "src/mod_fs/properties/create_stream_core.cpp", + "src/mod_fs/properties/fdopen_stream_core.cpp", + "src/mod_fs/properties/dup_core.cpp", + "src/mod_fs/properties/copy_listener/trans_listener_core.cpp", + "src/mod_fs/properties/listfile_core.cpp", + "src/mod_fs/properties/lstat_core.cpp", + "src/mod_fs/properties/lseek_core.cpp", + "src/mod_fs/properties/mkdir_core.cpp", + "src/mod_fs/properties/mkdtemp_core.cpp", + "src/mod_fs/properties/move_core.cpp", + "src/mod_fs/properties/movedir_core.cpp", + "src/mod_fs/properties/open_core.cpp", + "src/mod_fs/properties/read_core.cpp", + "src/mod_fs/properties/read_lines_core.cpp", + "src/mod_fs/properties/read_text_core.cpp", + "src/mod_fs/properties/rename_core.cpp", + "src/mod_fs/properties/rmdir_core.cpp", + "src/mod_fs/properties/stat_core.cpp", + "src/mod_fs/properties/symlink_core.cpp", + "src/mod_fs/properties/truncate_core.cpp", + "src/mod_fs/properties/unlink_core.cpp", + "src/mod_fs/properties/utimes_core.cpp", + "src/mod_fs/properties/write_core.cpp", + "src/mod_fs/properties/xattr_core.cpp", + ] + deps = [ + ":ohos_file_fs_abc_etc", + "${file_api_path}/interfaces/kits/native:remote_uri_native", + "${file_api_path}/interfaces/kits/native:task_signal_native", + "${file_api_path}/interfaces/kits/rust:rust_file", + "${utils_path}/filemgmt_libfs:filemgmt_libfs", + "${utils_path}/filemgmt_libhilog:filemgmt_libhilog", + ] + use_exceptions = true + external_deps = [ + "ability_runtime:ability_manager", + "app_file_service:fileuri_native", + "bundle_framework:appexecfwk_base", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "data_share:datashare_common", + "data_share:datashare_consumer", + "dfs_service:distributed_file_daemon_kit_inner", + "dfs_service:libdistributedfileutils", + "hilog:libhilog", + "hisysevent:libhisysevent", + "ipc:ipc_core", + "libuv:uv", + "runtime_core:ani", + "runtime_core:libarkruntime", + "samgr:samgr_proxy", + ] + + cflags = [ + "-fvisibility=hidden", + "-fdata-sections", + "-ffunction-sections", + "-Oz", + ] + cflags_cc = [ + "-std=c++17", + "-fvisibility-inlines-hidden", + "-Oz", + "-Wno-unused-function", + ] + branch_protector_ret = "pac_ret" + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + output_extension = "so" + subsystem_name = "filemanagement" + part_name = "file_api" +} + +generate_static_abc("ohos_file_fs_abc") { + base_url = "./src/mod_fs/ani/ets" + files = [ "./src/mod_fs/ani/ets/@ohos.file.fs.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/ohos_file_fs_abc.abc" +} + +ohos_prebuilt_etc("ohos_file_fs_abc_etc") { + source = "$target_out_dir/ohos_file_fs_abc.abc" + module_install_dir = "framework" + subsystem_name = "filemanagement" + part_name = "file_api" + deps = [ ":ohos_file_fs_abc" ] +} + +ohos_shared_library("ani_hash_class") { + public_configs = [ ":ani_config" ] + include_dirs = [ + "src/mod_hash", + "src/mod_hash/ani", + ] + sources = [ + "src/common/ani_helper/error_handler.cpp", + "src/common/ani_helper/type_converter.cpp", + "src/common/file_helper/fd_guard.cpp", + "src/common/file_helper/hash_file.cpp", + "src/mod_fs/fs_utils.cpp", + "src/mod_hash/ani/bind_function_class.cpp", + "src/mod_hash/ani/hash_ani.cpp", + "src/mod_hash/hash_core.cpp", + ] + + deps = [ + ":ohos_file_hash_abc_etc", + "${file_api_path}/interfaces/kits/rust:rust_file", + "${utils_path}/filemgmt_libfs:filemgmt_libfs", + "${utils_path}/filemgmt_libhilog:filemgmt_libhilog", + ] + external_deps = [ + "hilog:libhilog", + "libuv:uv", + "openssl:libcrypto_shared", + "runtime_core:ani", + "runtime_core:libarkruntime", + ] + use_exceptions = true + cflags = [ + "-fvisibility=hidden", + "-fdata-sections", + "-ffunction-sections", + "-Oz", + ] + cflags_cc = [ + "-fvisibility-inlines-hidden", + "-Oz", + ] + branch_protector_ret = "pac_ret" + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + output_extension = "so" + subsystem_name = "filemanagement" + part_name = "file_api" +} + +generate_static_abc("ohos_file_hash_abc") { + base_url = "./src/mod_hash/ani/ets" + files = [ "./src/mod_hash/ani/ets/@ohos.file.hash.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/ohos_file_hash_abc.abc" +} + +ohos_prebuilt_etc("ohos_file_hash_abc_etc") { + source = "$target_out_dir/ohos_file_hash_abc.abc" + module_install_dir = "framework" + subsystem_name = "filemanagement" + part_name = "file_api" + deps = [ ":ohos_file_hash_abc" ] +} + +ohos_shared_library("ani_securitylabel_class") { + public_configs = [ ":ani_config" ] + include_dirs = [ + "src/mod_securitylabel/ani", + "src/mod_securitylabel", + ] + sources = [ + "src/common/ani_helper/error_handler.cpp", + "src/common/ani_helper/type_converter.cpp", + "src/common/file_helper/fd_guard.cpp", + "src/mod_fs/fs_utils.cpp", + "src/mod_securitylabel/ani/bind_function_class.cpp", + "src/mod_securitylabel/ani/securitylabel_ani.cpp", + "src/mod_securitylabel/securitylabel_core.cpp", + ] + + deps = [ + ":ohos_file_securityLabel_abc_etc", + "${file_api_path}/interfaces/kits/rust:rust_file", + "${utils_path}/filemgmt_libfs:filemgmt_libfs", + "${utils_path}/filemgmt_libhilog:filemgmt_libhilog", + ] + external_deps = [ + "hilog:libhilog", + "libuv:uv", + "runtime_core:ani", + "runtime_core:libarkruntime", + ] + use_exceptions = true + cflags = [ + "-fvisibility=hidden", + "-fdata-sections", + "-ffunction-sections", + "-Oz", + ] + cflags_cc = [ + "-fvisibility-inlines-hidden", + "-Oz", + ] + branch_protector_ret = "pac_ret" + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + output_extension = "so" + subsystem_name = "filemanagement" + part_name = "file_api" +} + +generate_static_abc("ohos_file_securityLabel_abc") { + base_url = "./src/mod_securitylabel/ani/ets" + files = [ "./src/mod_securitylabel/ani/ets/@ohos.file.securityLabel.ets" ] + is_boot_abc = "True" + device_dst_file = "/system/framework/ohos_file_securityLabel_abc.abc" +} + +ohos_prebuilt_etc("ohos_file_securityLabel_abc_etc") { + source = "$target_out_dir/ohos_file_securityLabel_abc.abc" + module_install_dir = "framework" + subsystem_name = "filemanagement" + part_name = "file_api" + deps = [ ":ohos_file_securityLabel_abc" ] +} diff --git a/interfaces/kits/js/src/common/ani_helper/ani_helper.h b/interfaces/kits/js/src/common/ani_helper/ani_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..27ef05d38a58a9c0a57b0f1f1a19166494630636 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/ani_helper.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_ANI_ANI_HELPER_H +#define FILEMANAGEMENT_ANI_ANI_HELPER_H + +#include +#include +#include + +#include + +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +using namespace std; + +class AniHelper { +public: + template + static ani_status SetFieldValue( + ani_env *env, const ani_class &cls, ani_object &obj, const char *fieldName, const T &value) + { + ani_field field; + auto status = env->Class_FindField(cls, fieldName, &field); + if (status != ANI_OK) { + return status; + } + if constexpr (is_same_v || is_same_v || is_same_v) { + status = env->Object_SetField_Int(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + status = env->Object_SetField_Long(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + status = env->Object_SetField_Double(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + status = env->Object_SetField_Boolean(obj, field, value); + } else if constexpr (is_same_v || is_same_v) { + auto [succ, aniStr] = TypeConverter::ToAniString(env, value); + if (!succ) { + return ANI_ERROR; + } + status = env->Object_SetField_Ref(obj, field, move(aniStr)); + } else if constexpr (is_base_of_v) { + status = env->Object_SetField_Ref(obj, field, value); + } else { + return ANI_INVALID_TYPE; + } + return status; + } + + template + static ani_status SetPropertyValue( + ani_env *env, const ani_class &cls, ani_object &obj, const string &property, const T &value) + { + ani_method method; + string setter = "" + property; + auto status = env->Class_FindMethod(cls, setter.c_str(), nullptr, &method); + if (status != ANI_OK) { + return status; + } + + if constexpr (is_same_v || is_same_v) { + auto [succ, aniStr] = TypeConverter::ToAniString(env, value); + if (!succ) { + return ANI_ERROR; + } + status = env->Object_CallMethod_Void(obj, method, move(aniStr)); + } else if constexpr (is_base_of_v || is_same_v || is_same_v || + is_same_v || is_same_v || is_same_v || + is_same_v || is_same_v || is_same_v || + is_same_v) { + status = env->Object_CallMethod_Void(obj, method, value); + } else { + return ANI_INVALID_TYPE; + } + return status; + } + + static tuple> ParseInt64Option(ani_env *env, ani_object obj, const string &tag) + { + ani_boolean isUndefined = true; + ani_ref property; + ani_status status = ANI_ERROR; + status = env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &property); + if (status != ANI_OK) { + return { false, nullopt }; + } + env->Reference_IsUndefined(property, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + ani_long value; + status = env->Object_CallMethodByName_Long(static_cast(property), "longValue", ":J", &value); + if (status != ANI_OK) { + return { false, nullopt }; + } + auto result = make_optional(static_cast(value)); + return { true, move(result) }; + } + + static tuple> ParseEncoding(ani_env *env, ani_object obj) + { + ani_boolean isUndefined; + ani_ref property; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, "encoding", &property)) { + return { false, nullopt }; + } + env->Reference_IsUndefined(property, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + auto [succ, encoding] = TypeConverter::ToUTF8String(env, (ani_string)property); + if (!succ) { + return { false, nullopt }; + } + return { true, make_optional(move(encoding)) }; + } + + static ani_env* GetThreadEnv(ani_vm *vm) + { + static thread_local ani_env *env {nullptr}; + if (env != nullptr) { + return env; + } + + ani_option interopEnabled {"--interop=enable", nullptr}; + ani_options aniArgs {1, &interopEnabled}; + auto status = vm->AttachCurrentThread(&aniArgs, ANI_VERSION_1, &env); + if (status != ANI_OK) { + status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + HILOGE("vm GetEnv, err: %{private}d", status); + return nullptr; + } + + return env; + } + + return env; + } +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI + +#endif // FILEMANAGEMENT_ANI_ANI_HELPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/bind_function.h b/interfaces/kits/js/src/common/ani_helper/bind_function.h new file mode 100644 index 0000000000000000000000000000000000000000..3c951b25125364260b1879851df4f1b832e9b233 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/bind_function.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_ANI_BIND_FUNCTION_H +#define FILEMANAGEMENT_ANI_BIND_FUNCTION_H + +#include +#include +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +template +ANI_EXPORT ani_status BindClass(ani_env *env, const char *className, const std::array &methods) +{ + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + + if (className == nullptr) { + HILOGE("Invalid parameter className"); + return ANI_INVALID_ARGS; + } + + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class '%{private}s'", className); + return ANI_NOT_FOUND; + } + + if (ANI_OK != env->Class_BindNativeMethods(cls, methods.data(), methods.size())) { + HILOGE("Cannot bind native methods to '%{private}s'", className); + return ANI_ERROR; + }; + return ANI_OK; +} + +template +ANI_EXPORT ani_status BindNamespace( + ani_env *env, const char *namespaceStr, const std::array &methods) +{ + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + + if (namespaceStr == nullptr) { + HILOGE("Invalid parameter namespaceStr"); + return ANI_INVALID_ARGS; + } + + ani_namespace ns; + if (ANI_OK != env->FindNamespace(namespaceStr, &ns)) { + HILOGE("Cannot find namespace '%{private}s'", namespaceStr); + return ANI_NOT_FOUND; + } + + if (ANI_OK != env->Namespace_BindNativeFunctions(ns, methods.data(), methods.size())) { + HILOGE("Cannot bind native methods to '%{private}s'", namespaceStr); + return ANI_ERROR; + }; + return ANI_OK; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // FILEMANAGEMENT_ANI_BIND_FUNCTION_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/error_handler.cpp b/interfaces/kits/js/src/common/ani_helper/error_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a9e87cb828a602ae4995180c6b59a41a66c8dfb7 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/error_handler.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 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 "error_handler.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +ani_status ErrorHandler::Throw(ani_env *env, int32_t code, const std::string &errMsg) +{ + const char *className = "L@ohos/base/BusinessError;"; + const char *name = "BusinessError"; + return Throw(env, className, name, code, errMsg); +} + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/error_handler.h b/interfaces/kits/js/src/common/ani_helper/error_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..59c41c11436572d555aab35aa47ee003427564ef --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/error_handler.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_ANI_ERROR_HANDLER_H +#define FILEMANAGEMENT_ANI_ERROR_HANDLER_H + +#include +#include +#include +#include "ani_helper.h" +#include "filemgmt_libhilog.h" +#include "fs_error.h" +#include "type_converter.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +class ErrorHandler { +public: + static ani_status Throw(ani_env *env, int32_t code, const std::string &errMsg); + + static ani_status Throw(ani_env *env, int32_t code) + { + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + FsError err(code); + return Throw(env, std::move(err)); + } + + static ani_status Throw(ani_env *env, const FsError &err) + { + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + auto code = err.GetErrNo(); + const auto &errMsg = err.GetErrMsg(); + return Throw(env, code, errMsg); + } + +private: + static ani_status Throw( + ani_env *env, const char *className, const char *name, int32_t code, const std::string &errMsg) + { + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return ANI_INVALID_ARGS; + } + + if (className == nullptr) { + HILOGE("Invalid parameter className"); + return ANI_INVALID_ARGS; + } + + if (name == nullptr) { + HILOGE("Invalid parameter name"); + return ANI_INVALID_ARGS; + } + + auto [status, err] = CreateErrorObj(env, className, name, code, errMsg); + + if (status != ANI_OK) { + HILOGE("Create error object failed!"); + return status; + } + + status = env->ThrowError(err); + if (status != ANI_OK) { + HILOGE("Throw ani error object failed!"); + return status; + } + return ANI_OK; + } + + static std::tuple CreateErrorObj( + ani_env *env, const char *className, const char *name, int32_t code, const std::string &errMsg) + { + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class '%{private}s'", className); + return { ANI_NOT_FOUND, nullptr }; + } + + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", ":V", &ctor)) { + HILOGE("Cannot find constructor for class '%{private}s'", className); + return { ANI_NOT_FOUND, nullptr }; + } + + auto [succ, message] = TypeConverter::ToAniString(env, errMsg); + if (!succ) { + HILOGE("Convert errMsg to ani string failed"); + return { ANI_ERROR, nullptr }; + } + + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, static_cast(code), message)) { + HILOGE("Cannot create ani error object"); + return { ANI_ERROR, nullptr }; + } + + ani_status status = ANI_ERROR; + status = AniHelper::SetFieldValue(env, cls, obj, "name", name); + if (status != ANI_OK) { + HILOGE("Set field 'name' value failed"); + return { status, nullptr }; + } + + status = AniHelper::SetFieldValue(env, cls, obj, "message", errMsg); + if (status != ANI_OK) { + HILOGE("Set field 'message' value failed"); + return { status, nullptr }; + } + + status = AniHelper::SetFieldValue(env, cls, obj, "code", static_cast(code)); + if (status != ANI_OK) { + HILOGE("Set field 'code' value failed"); + return { status, nullptr }; + } + ani_error err = static_cast(obj); + return { ANI_OK, std::move(err) }; + } +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI + +#endif // FILEMANAGEMENT_ANI_ERROR_HANDLER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/type_converter.cpp b/interfaces/kits/js/src/common/ani_helper/type_converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e618699674ad19375fb59c8391765074e448a6d9 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/type_converter.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2025 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 "type_converter.h" + +#include +#include +#include + +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +std::tuple TypeConverter::ToUTF8String(ani_env *env, const ani_string &path) +{ + if (env == nullptr) { + return { false, EMPTY_STRING }; + } + ani_size sz {}; + std::string result; + auto status = env->String_GetUTF8Size(path, &sz); + if (status != ANI_OK) { + return { false, EMPTY_STRING }; + } + result.resize(sz + 1); + status = env->String_GetUTF8SubString(path, 0, sz, result.data(), result.size(), &sz); + if (status != ANI_OK) { + return { false, EMPTY_STRING }; + } + result.resize(sz); + return { true, std::move(result) }; +} + +std::tuple> TypeConverter::ToOptionalInt32(ani_env *env, const ani_object &value) +{ + if (env == nullptr) { + return { false, {} }; + } + ani_boolean isUndefined; + env->Reference_IsUndefined(value, &isUndefined); + if (isUndefined) { + return { true, std::nullopt }; + } + + ani_double doubleValue; + if (ANI_OK == env->Object_CallMethodByName_Double(value, "doubleValue", nullptr, &doubleValue)) { + return { true, std::make_optional(static_cast(doubleValue)) }; + } + + ani_int intValue; + if (ANI_OK == env->Object_CallMethodByName_Int(value, "intValue", nullptr, &intValue)) { + return { true, std::make_optional(intValue) }; + } + + return { false, {} }; +} + +std::tuple> TypeConverter::ToOptionalInt64(ani_env *env, const ani_object &value) +{ + if (env == nullptr) { + return { false, {} }; + } + + ani_boolean isUndefined; + env->Reference_IsUndefined(value, &isUndefined); + if (isUndefined) { + return { true, std::nullopt }; + } + + ani_double doubleValue; + if (ANI_OK == env->Object_CallMethodByName_Double(value, "doubleValue", nullptr, &doubleValue)) { + return { true, std::make_optional(static_cast(doubleValue)) }; + } + + ani_long longValue; + if (ANI_OK == env->Object_CallMethodByName_Long(value, "longValue", nullptr, &longValue)) { + return { true, std::make_optional(longValue) }; + } + + return { false, {} }; +} + +std::tuple TypeConverter::ToAniString(ani_env *env, std::string str) +{ + if (env == nullptr) { + return { false, {} }; + } + + ani_string result; + if (ANI_OK != env->String_NewUTF8(str.c_str(), str.size(), &result)) { + return { false, {} }; + } + return { true, std::move(result) }; +} + +std::tuple TypeConverter::ToAniString(ani_env *env, const char *str) +{ + if (env == nullptr) { + return { false, {} }; + } + + size_t length = std::strlen(str); + ani_string result; + if (ANI_OK != env->String_NewUTF8(str, length, &result)) { + return { false, {} }; + } + return { true, std::move(result) }; +} + +std::tuple> TypeConverter::EnumToInt32(ani_env *env, const ani_enum_item &enumOp) +{ + ani_boolean isUndefined; + env->Reference_IsUndefined(enumOp, &isUndefined); + if (isUndefined) { + return { true, std::nullopt }; + } + + ani_int result; + if (ANI_OK != env->EnumItem_GetValue_Int(enumOp, &result)) { + return { false, {} }; + } + + return { true, std::make_optional(result) }; +} + +static std::tuple ParseFd(ani_env *env, const ani_object &pathOrFd) +{ + ani_boolean isFd = false; + + ani_class DoubleClass; + env->FindClass("Lstd/core/Double;", &DoubleClass); + env->Object_InstanceOf(pathOrFd, DoubleClass, &isFd); + if (isFd) { + ani_double doubleValue; + if (ANI_OK != env->Object_CallMethodByName_Double(pathOrFd, "doubleValue", nullptr, &doubleValue)) { + HILOGE("Parse file path failed"); + return { false, 0 }; + } + int32_t fd = static_cast(doubleValue); + return { true, fd }; + } + + ani_class IntClass; + env->FindClass("Lstd/core/Int;", &IntClass); + env->Object_InstanceOf(pathOrFd, IntClass, &isFd); + if (isFd) { + ani_int fd; + if (ANI_OK != env->Object_CallMethodByName_Int(pathOrFd, "intValue", nullptr, &fd)) { + HILOGE("Parse file path failed"); + return { false, 0 }; + } + return { true, fd }; + } + + return { false, 0 }; +} + +std::tuple TypeConverter::ToFileInfo(ani_env *env, const ani_object &pathOrFd) +{ + if (env == nullptr) { + HILOGE("Invalid parameter env"); + return { false, FileInfo { false, {}, {} } }; + } + + ani_class stringClass; + env->FindClass("Lstd/core/String;", &stringClass); + + ani_boolean isPath = false; + env->Object_InstanceOf(pathOrFd, stringClass, &isPath); + if (isPath) { + auto [succ, path] = TypeConverter::ToUTF8String(env, static_cast(pathOrFd)); + if (!succ) { + HILOGE("Parse file path failed"); + return { false, FileInfo { false, {}, {} } }; + } + size_t length = path.length() + 1; + auto chars = std::make_unique(length); + auto ret = strncpy_s(chars.get(), length, path.c_str(), length - 1); + if (ret != EOK) { + HILOGE("Copy file path failed!"); + return { false, FileInfo { false, {}, {} } }; + } + return { true, FileInfo { true, move(chars), {} } }; + } + + auto [isFd, fd] = ParseFd(env, pathOrFd); + if (isFd) { + auto fdg = CreateUniquePtr(fd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + return { false, FileInfo { false, {}, {} } }; + } + return { true, FileInfo { false, {}, move(fdg) } }; + } + + return { false, FileInfo { false, {}, {} } }; +} + +std::tuple TypeConverter::ToArrayBuffer(ani_env *env, ani_arraybuffer &buffer) +{ + if (env == nullptr) { + return { false, ArrayBuffer { nullptr, 0 } }; + } + + void *buf = nullptr; + ani_size length = 0; + + if (ANI_OK != env->ArrayBuffer_GetInfo(buffer, &buf, &length)) { + return { false, ArrayBuffer { nullptr, 0 } }; + } + return { true, ArrayBuffer { std::move(buf), length } }; +} + +std::tuple TypeConverter::ToAniStringList( + ani_env *env, const std::string strList[], const uint32_t length) +{ + if (env == nullptr) { + return { false, nullptr }; + } + + ani_array_ref result = nullptr; + ani_class itemCls = nullptr; + if (env->FindClass("Lstd/core/String;", &itemCls) != ANI_OK) { + return { false, result }; + } + if (env->Array_New_Ref(itemCls, length, nullptr, &result) != ANI_OK) { + return { false, result }; + } + for (int i = 0; i < length; i++) { + auto [ret, item] = TypeConverter::ToAniString(env, strList[i]); + if (!ret) { + return { false, nullptr }; + } + + if (env->Array_Set_Ref(result, i, item) != ANI_OK) { + return { false, nullptr }; + } + } + return { true, result }; +} + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI \ No newline at end of file diff --git a/interfaces/kits/js/src/common/ani_helper/type_converter.h b/interfaces/kits/js/src/common/ani_helper/type_converter.h new file mode 100644 index 0000000000000000000000000000000000000000..24bdd736a736c1c26e1deadc3d1dc351573e2817 --- /dev/null +++ b/interfaces/kits/js/src/common/ani_helper/type_converter.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_ANI_TYPE_CONVERTER_H +#define FILEMANAGEMENT_ANI_TYPE_CONVERTER_H + +#include +#include + +#include + +#include "fs_array_buffer.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { +inline const std::string EMPTY_STRING = ""; + +class TypeConverter { +public: + static std::tuple ToUTF8String(ani_env *env, const ani_string &path); + static std::tuple> ToOptionalInt32(ani_env *env, const ani_object &value); + static std::tuple> ToOptionalInt64(ani_env *env, const ani_object &value); + static std::tuple ToAniString(ani_env *env, std::string str); + static std::tuple ToAniString(ani_env *env, const char *str); + static std::tuple> EnumToInt32(ani_env *env, const ani_enum_item &enumOp); + static std::tuple ToFileInfo(ani_env *env, const ani_object &pathOrFd); + static std::tuple ToArrayBuffer(ani_env *env, ani_arraybuffer &buffer); + static std::tuple ToAniStringList( + ani_env *env, const std::string strList[], const uint32_t length); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO::ANI + +#endif // FILEMANAGEMENT_ANI_TYPE_CONVERTER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/fs_file_filter.h b/interfaces/kits/js/src/common/fs_file_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..f16c178213255dd738a7c62d64419e0d7adf6271 --- /dev/null +++ b/interfaces/kits/js/src/common/fs_file_filter.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2025 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 FS_FILE_FILTER_H +#define FS_FILE_FILTER_H + +#include +#include +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class FsFileFilter { +public: + FsFileFilter() = default; + ~FsFileFilter() = default; + + FsFileFilter(const FsFileFilter &filter) = default; + FsFileFilter &operator=(const FsFileFilter &filter) = default; + + void SetSuffix(const std::optional> &suffix) + { + suffix_ = std::move(suffix); + } + + const std::optional> &GetSuffix() const + { + return suffix_; + } + + void SetDisplayName(const std::optional> &displayName) + { + displayName_ = std::move(displayName); + } + + const std::optional> &GetDisplayName() const + { + return displayName_; + } + + void SetMimeType(const std::optional> &mimeType) + { + mimeType_ = std::move(mimeType); + } + + const std::optional> &GetMimeType() const + { + return mimeType_; + } + + void SetFileSizeOver(const std::optional &fileSizeOver) + { + fileSizeOver_ = std::move(fileSizeOver); + } + + const std::optional &GetFileSizeOver() const + { + return fileSizeOver_; + } + + void SetLastModifiedAfter(const std::optional &lastModifiedAfter) + { + lastModifiedAfter_ = std::move(lastModifiedAfter); + } + + const std::optional &GetLastModifiedAfter() const + { + return lastModifiedAfter_; + } + + void SetExcludeMedia(const bool &excludeMedia) + { + excludeMedia_ = excludeMedia; + } + + bool GetExcludeMedia() const + { + return excludeMedia_; + } + + void SetHasFilter(const bool &hasFilter) + { + hasFilter_ = hasFilter; + } + + bool GetHasFilter() const + { + return hasFilter_; + } + +private: + std::optional> suffix_ = std::nullopt; + std::optional> displayName_ = std::nullopt; + std::optional> mimeType_ = std::nullopt; + std::optional fileSizeOver_ = std::nullopt; + std::optional lastModifiedAfter_ = std::nullopt; + bool excludeMedia_ = false; + bool hasFilter_ = false; +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // FS_FILE_FILTER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/common/fs_filefiter.h b/interfaces/kits/js/src/common/fs_filefiter.h new file mode 100644 index 0000000000000000000000000000000000000000..f16c178213255dd738a7c62d64419e0d7adf6271 --- /dev/null +++ b/interfaces/kits/js/src/common/fs_filefiter.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2025 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 FS_FILE_FILTER_H +#define FS_FILE_FILTER_H + +#include +#include +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class FsFileFilter { +public: + FsFileFilter() = default; + ~FsFileFilter() = default; + + FsFileFilter(const FsFileFilter &filter) = default; + FsFileFilter &operator=(const FsFileFilter &filter) = default; + + void SetSuffix(const std::optional> &suffix) + { + suffix_ = std::move(suffix); + } + + const std::optional> &GetSuffix() const + { + return suffix_; + } + + void SetDisplayName(const std::optional> &displayName) + { + displayName_ = std::move(displayName); + } + + const std::optional> &GetDisplayName() const + { + return displayName_; + } + + void SetMimeType(const std::optional> &mimeType) + { + mimeType_ = std::move(mimeType); + } + + const std::optional> &GetMimeType() const + { + return mimeType_; + } + + void SetFileSizeOver(const std::optional &fileSizeOver) + { + fileSizeOver_ = std::move(fileSizeOver); + } + + const std::optional &GetFileSizeOver() const + { + return fileSizeOver_; + } + + void SetLastModifiedAfter(const std::optional &lastModifiedAfter) + { + lastModifiedAfter_ = std::move(lastModifiedAfter); + } + + const std::optional &GetLastModifiedAfter() const + { + return lastModifiedAfter_; + } + + void SetExcludeMedia(const bool &excludeMedia) + { + excludeMedia_ = excludeMedia; + } + + bool GetExcludeMedia() const + { + return excludeMedia_; + } + + void SetHasFilter(const bool &hasFilter) + { + hasFilter_ = hasFilter; + } + + bool GetHasFilter() const + { + return hasFilter_; + } + +private: + std::optional> suffix_ = std::nullopt; + std::optional> displayName_ = std::nullopt; + std::optional> mimeType_ = std::nullopt; + std::optional fileSizeOver_ = std::nullopt; + std::optional lastModifiedAfter_ = std::nullopt; + bool excludeMedia_ = false; + bool hasFilter_ = false; +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // FS_FILE_FILTER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/ani/bind_function_class.cpp b/interfaces/kits/js/src/mod_fs/ani/bind_function_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ecc8b5a41aee8c51f422145a8a83d130dd016cd --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/ani/bind_function_class.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2025 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 + +#include + +#include "access_ani.h" +#include "bind_function.h" +#include "close_ani.h" +#include "copy_ani.h" +#include "copy_file_ani.h" +#include "create_randomaccessfile_ani.h" +#include "fdatasync_ani.h" +#include "create_stream_ani.h" +#include "fdopen_stream_ani.h" +#include "dup_ani.h" +#include "file_ani.h" +#include "filemgmt_libhilog.h" +#include "fsync_ani.h" +#include "listfile_ani.h" +#include "lstat_ani.h" +#include "lseek_ani.h" +#include "mkdir_ani.h" +#include "mkdtemp_ani.h" +#include "move_ani.h" +#include "movedir_ani.h" +#include "open_ani.h" +#include "randomaccessfile_ani.h" +#include "read_ani.h" +#include "read_lines_ani.h" +#include "read_text_ani.h" +#include "reader_iterator_ani.h" +#include "rename_ani.h" +#include "rmdir_ani.h" +#include "stat_ani.h" +#include "stream_ani.h" +#include "symlink_ani.h" +#include "task_signal_ani.h" +#include "truncate_ani.h" +#include "unlink_ani.h" +#include "write_ani.h" +#include "xattr_ani.h" +#include "utimes_ani.h" + +using namespace OHOS::FileManagement::ModuleFileIO::ANI; + +static ani_status BindRafFileMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/RandomAccessFileInner;"; + + std::array methods = { + ani_native_function { "setFilePointer0", nullptr, + reinterpret_cast(RandomAccessFileAni::SetFilePointer) }, + ani_native_function { "close", nullptr, reinterpret_cast(RandomAccessFileAni::Close) }, + ani_native_function { "writeSync0", nullptr, reinterpret_cast(RandomAccessFileAni::WriteSync) }, + ani_native_function { "readSync0", nullptr, reinterpret_cast(RandomAccessFileAni::ReadSync) }, + }; + + return BindClass(env, className, methods); +} + +static ani_status BindFileMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/FileInner;"; + + std::array methods = { + ani_native_function { "getParent", nullptr, reinterpret_cast(FileAni::GetParent) }, + ani_native_function { "lockSync", nullptr, reinterpret_cast(FileAni::LockSync) }, + ani_native_function { "tryLock", nullptr, reinterpret_cast(FileAni::TryLock) }, + ani_native_function { "unlock", nullptr, reinterpret_cast(FileAni::UnLock) }, + }; + + return BindClass(env, className, methods); +} + +static ani_status BindReaderIteratorMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/ReaderIteratorInner;"; + + std::array methods = { + ani_native_function { "next", nullptr, reinterpret_cast(ReaderIteratorAni::Next) }, + }; + + return BindClass(env, className, methods); +} + +static ani_status BindStatClassMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/StatInner;"; + + std::array methods = { + ani_native_function { "isBlockDevice", ":Z", reinterpret_cast(StatAni::IsBlockDevice) }, + ani_native_function { "isCharacterDevice", ":Z", reinterpret_cast(StatAni::IsCharacterDevice) }, + ani_native_function { "isDirectory", ":Z", reinterpret_cast(StatAni::IsDirectory) }, + ani_native_function { "isFIFO", ":Z", reinterpret_cast(StatAni::IsFIFO) }, + ani_native_function { "isFile", ":Z", reinterpret_cast(StatAni::IsFile) }, + ani_native_function { "isSocket", ":Z", reinterpret_cast(StatAni::IsSocket) }, + ani_native_function { "isSymbolicLink", ":Z", reinterpret_cast(StatAni::IsSymbolicLink) }, + }; + + return BindClass(env, className, methods); +} + +static ani_status BindStreamMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/StreamInner;"; + + std::array methods = { + ani_native_function { "closeSync", nullptr, reinterpret_cast(StreamAni::Close) }, + ani_native_function { "flushSync", nullptr, reinterpret_cast(StreamAni::Flush) }, + ani_native_function { "readSync", nullptr, reinterpret_cast(StreamAni::Read) }, + ani_native_function { "writeSync", nullptr, reinterpret_cast(StreamAni::Write) }, + ani_native_function { "seek", nullptr, reinterpret_cast(StreamAni::Seek) }, + }; + + return BindClass(env, className, methods); +} + +static ani_status BindTaskSignalClassMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/TaskSignal;"; + + std::array methods = { + ani_native_function { "cancel", ":V", reinterpret_cast(TaskSignalAni::Cancel) }, + ani_native_function { "onCancelNative", nullptr, reinterpret_cast(TaskSignalAni::OnCancel) }, + }; + + return BindClass(env, className, methods); +} + +static ani_status BindStaticMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/fs/FileIoImpl;"; + + std::array methods = { + ani_native_function { "closeSync", nullptr, reinterpret_cast(CloseAni::CloseSync) }, + ani_native_function { "copySync", nullptr, reinterpret_cast(CopyAni::CopySync) }, + ani_native_function { "copyFileSync", nullptr, reinterpret_cast(CopyFileAni::CopyFileSync) }, + ani_native_function { "createRandomAccessFileSync", nullptr, reinterpret_cast( + CreateRandomAccessFileAni::CreateRandomAccessFileSync) }, + ani_native_function { "doAccessSync", nullptr, reinterpret_cast(AccessAni::AccessSync3) }, + ani_native_function { "fsyncSync", nullptr, reinterpret_cast(FsyncAni::FsyncSync) }, + ani_native_function { "fdatasyncSync", nullptr, reinterpret_cast(FDataSyncAni::FDataSyncSync) }, + ani_native_function { "getxattrSync", nullptr, reinterpret_cast(XattrAni::GetXattrSync) }, + ani_native_function { + "createStreamSync", nullptr, reinterpret_cast(CreateStreamAni::CreateStreamSync) }, + ani_native_function { "doAccessSync", nullptr, reinterpret_cast(AccessAni::AccessSync3) }, + ani_native_function { + "fdopenStreamSync", nullptr, reinterpret_cast(FdopenStreamAni::FdopenStreamSync) }, + ani_native_function { "dup", nullptr, reinterpret_cast(DupAni::Dup) }, + ani_native_function { "listFileSync", nullptr, reinterpret_cast(ListFileAni::ListFileSync) }, + ani_native_function { "lstatSync", nullptr, reinterpret_cast(LstatAni::LstatSync) }, + ani_native_function { "lseekSync", nullptr, reinterpret_cast(LseekAni::LseekSync) }, + ani_native_function { "mkdirSync", "Lstd/core/String;:V", reinterpret_cast(MkdirkAni::MkdirSync0) }, + ani_native_function { "mkdirSync", "Lstd/core/String;Z:V", reinterpret_cast(MkdirkAni::MkdirSync1) }, + ani_native_function { "movedirSync", nullptr, reinterpret_cast(MoveDirAni::MoveDirSync) }, + ani_native_function { "mkdtempSync", nullptr, reinterpret_cast(MkdtempAni::MkdtempSync) }, + ani_native_function { "moveFileSync", nullptr, reinterpret_cast(MoveAni::MoveFileSync) }, + ani_native_function { "openSync", nullptr, reinterpret_cast(OpenAni::OpenSync) }, + ani_native_function { "readlinesSync", nullptr, reinterpret_cast(ReadLinesAni::ReadLinesSync) }, + ani_native_function { "readSync", nullptr, reinterpret_cast(ReadAni::ReadSync) }, + ani_native_function { "readTextSync", nullptr, reinterpret_cast(ReadTextAni::ReadTextSync) }, + ani_native_function { "renameSync", nullptr, reinterpret_cast(RenameAni::RenameSync) }, + ani_native_function { "rmdirSync", nullptr, reinterpret_cast(RmdirAni::RmdirSync) }, + ani_native_function { "setxattrSync", nullptr, reinterpret_cast(XattrAni::SetXattrSync) }, + ani_native_function { "statSync", nullptr, reinterpret_cast(StatAni::StatSync) }, + ani_native_function { "symlinkSync", nullptr, reinterpret_cast(SymlinkAni::SymlinkSync) }, + ani_native_function { "truncateSync", nullptr, reinterpret_cast(TruncateAni::TruncateSync) }, + ani_native_function { "unlinkSync", nullptr, reinterpret_cast(UnlinkAni::UnlinkSync) }, + ani_native_function { "writeSync", nullptr, reinterpret_cast(WriteAni::WriteSync) }, + ani_native_function { "utimes", nullptr, reinterpret_cast(UtimesAni::Utimes) }, + }; + return BindClass(env, className, methods); +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + if (vm == nullptr) { + HILOGE("Invalid parameter vm"); + return ANI_INVALID_ARGS; + } + + if (result == nullptr) { + HILOGE("Invalid parameter result"); + return ANI_INVALID_ARGS; + } + + ani_env *env; + ani_status status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + HILOGE("Invalid ani version!"); + return ANI_INVALID_VERSION; + } + + if ((status = BindStaticMethods(env)) != ANI_OK) { + HILOGE("Cannot bind native static methods for BindStaticMethods!"); + return status; + }; + + if ((status = BindFileMethods) != ANI_OK) { + HILOGE("Cannot bind native methods for file Class"); + return status; + }; + + if ((status = BindReaderIteratorMethods(env)) != ANI_OK) { + HILOGE("Cannot bind native methods for ReaderIterator Class"); + return status; + }; + + if ((status = BindStatClassMethods(env)) != ANI_OK) { + HILOGE("Cannot bind native methods for Stat Class!"); + return status; + }; + + if ((status = BindRafFileMethods(env)) != ANI_OK) { + HILOGE("Cannot bind native methods for RafFile Class"); + return status; + }; + + if ((status = BindStreamMethods(env)) != ANI_OK) { + HILOGE("Cannot bind native methods for Stream Class!"); + return status; + }; + + if ((status = BindTaskSignalClassMethods(env)) != ANI_OK) { + HILOGE("Cannot bind native methods for TaskSignal Class!"); + return status; + }; + + *result = ANI_VERSION_1; + return ANI_OK; +} diff --git a/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets b/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets new file mode 100644 index 0000000000000000000000000000000000000000..490a80cae9020e91cf8428233f51728988970dc1 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/ani/ets/@ohos.file.fs.ets @@ -0,0 +1,2003 @@ +/* + * Copyright (c) 2025 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. + */ +import { BusinessError, AsyncCallback } from '@ohos.base'; +import stream from '@ohos.util.stream'; + +function access(path: string, mode?: AccessModeType): Promise { + return new Promise((resolve: (result: boolean) => void, reject: (e: BusinessError) => void) => { + if (mode === undefined) { + let promise = taskpool.execute((path: string): boolean => { + return FileIoImpl.doAccessSync(path); + }, path); + promise.then((ret: NullishType) => { + let result = ret as boolean; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((path: string, mode: AccessModeType): boolean => { + return FileIoImpl.doAccessSync(path, mode); + }, path, mode); + promise.then((ret: NullishType) => { + let result = ret as boolean; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function access(path: string, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string): boolean => { + return FileIoImpl.doAccessSync(path); + }, path); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as boolean; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, false); + }); +} + +function access(path: string, mode: AccessModeType, flag: AccessFlagType): Promise { + return new Promise((resolve: (result: boolean) => void, reject: (e: BusinessError) => void) => { + let promise = taskpool.execute(FileIoImpl.doAccessSync, path, mode, flag); + promise.then((ret: NullishType): void => { + let result = ret as boolean; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + }) +} + +function accessSync(path: string, mode?: AccessModeType): boolean { + return FileIoImpl.doAccessSync(path, mode); +} + +function accessSync(path: string, mode: AccessModeType, flag: AccessFlagType): boolean { + return FileIoImpl.doAccessSync(path, mode, flag); +} + +function close(file: number | File): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((file: number | File): undefined => FileIoImpl.closeSync(file), file); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function close(file: number | File, callback: AsyncCallback): void { + let promise = taskpool.execute((file: number | File): undefined => FileIoImpl.closeSync(file), file); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function closeSync(file: number | File): void { + return FileIoImpl.closeSync(file) +} + +function getxattrSync(path: string, key: string): string { + return FileIoImpl.getxattrSync(path, key) +} + +function getxattr(path: string, key: string): Promise { + return new Promise((resolve: (result: string) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute(FileIoImpl.getxattrSync, path, key); + promise.then((ret: NullishType): void => { + let result = ret as string; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function dup(fd: number): File { + return FileIoImpl.dup(fd); +} + +function mkdirSync(path: string): void { + return FileIoImpl.mkdirSync(path) +} + +function fdatasyncSync(fd: number): void { + return FileIoImpl.fdatasyncSync(fd) +} + +function fdatasync(fd: number): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((fd: number): undefined => FileIoImpl.fdatasyncSync(fd), fd); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e as BusinessError); + }); + }); +} + +function fdatasync(fd: number, callback: AsyncCallback): void { + let promise = taskpool.execute((fd: number): undefined => FileIoImpl.fdatasyncSync(fd), fd); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function mkdirSync(path: string, recursion: boolean): void { + return FileIoImpl.mkdirSync(path, recursion) +} + +function mkdirSync1(path: string): undefined { + FileIoImpl.mkdirSync(path); + return undefined; +} + +function mkdirSync2(path: string, recursion: boolean): undefined { + FileIoImpl.mkdirSync(path, recursion); + return undefined; +} + +function mkdir(path: string): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string): undefined => mkdirSync1(path), path); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e as BusinessError); + }); + }); +} + +function mkdir(path: string, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string): undefined => mkdirSync1(path), path); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function mkdir(path: string, recursion: boolean): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string, recursion: boolean): undefined => + mkdirSync2(path, recursion), path, recursion); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: NullishType): void => { + reject(e as BusinessError); + }); + }); +} + +function mkdir(path: string, recursion: boolean, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string, recursion: boolean): undefined => + mkdirSync2(path, recursion), path, recursion); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function moveDirSync(src: string, dest: string, mode?: number): void { + return FileIoImpl.movedirSync(src, dest, mode) +} + +function moveDir(src: string, dest: string, mode?: number): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + if (mode === undefined) { + let promise = taskpool.execute((src: string, dest: string): undefined => { + return FileIoImpl.movedirSync(src, dest); + }, src, dest); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((src: string, dest: string, mode: number): undefined => { + return FileIoImpl.movedirSync(src, dest, mode); + }, src, dest, mode); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }) +} + +function moveDir(src: string, dest: string, callback: AsyncCallback): void { + let promise = taskpool.execute((src: string, dest: string): undefined => { + return FileIoImpl.movedirSync(src, dest); + }, src, dest); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function moveDir(src: string, dest: string, mode: number, callback: AsyncCallback): void { + let promise = taskpool.execute((src: string, dest: string, mode: number): undefined => { + return FileIoImpl.movedirSync(src, dest, mode); + }, src, dest, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function mkdtempSync(prefix: string): string { + return FileIoImpl.mkdtempSync(prefix); +} + +function mkdtemp(prefix: string): Promise { + return new Promise((resolve: (result: string) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute(FileIoImpl.mkdtempSync, prefix); + promise.then((ret: NullishType): void => { + let result = ret as string; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function mkdtemp(prefix: string, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.mkdtempSync, prefix); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as string; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, ""); + }); +} + +function moveFileSync(src: string, dest: string, mode?: number): void { + return FileIoImpl.moveFileSync(src, dest, mode); +} + +function moveFile(src: string, dest: string, mode?: number): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + if (mode === undefined) { + let promise = taskpool.execute((src: string, dest: string): undefined => { + return FileIoImpl.moveFileSync(src, dest); + }, src, dest); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((src: string, dest: string, mode: number): undefined => { + return FileIoImpl.moveFileSync(src, dest, mode); + }, src, dest, mode); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function moveFile(src: string, dest: string, mode: number, callback: AsyncCallback): void { + let promise = taskpool.execute((src: string, dest: string, mode: number): undefined => { + return FileIoImpl.moveFileSync(src, dest, mode); + }, src, dest, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function moveFile(src: string, dest: string, callback: AsyncCallback): void { + let promise = taskpool.execute((src: string, dest: string): undefined => { + return FileIoImpl.moveFileSync(src, dest); + }, src, dest); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function openSync(path: string, mode?: number): File { + return FileIoImpl.openSync(path, mode); +} + +function open(path: String, mode?: number): Promise { + return new Promise((resolve: (result: File) => void, reject: (e: BusinessError) => void) => { + if (mode === undefined) { + let promise = taskpool.execute(FileIoImpl.openSync, path); + promise.then((ret: NullishType): void => { + let file = ret as File; + resolve(file); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(FileIoImpl.openSync, path, mode); + promise.then((ret: NullishType): void => { + let file = ret as File; + resolve(file); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function open(path: String, mode: number, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.openSync, path, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let file = ret as File; + callback(e, file); + }).catch((e: BusinessError): void => { + let f: File = new FileInner(0); + callback(e, f); + }); +} + +function open(path: String, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.openSync, path); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let file = ret as File; + callback(e, file); + }).catch((e: BusinessError): void => { + let f: File = new FileInner(0); + callback(e, f); + }); +} + +function writeSync(fd: number, buffer: string | ArrayBuffer, options?: WriteOptions): number { + return FileIoImpl.writeSync(fd, buffer, options); +} + +function write(fd: number, buffer: string | ArrayBuffer, options?: WriteOptions): Promise { + return new Promise((resolve: (result: number) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(FileIoImpl.writeSync, fd, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(FileIoImpl.writeSync, fd, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function write(fd: number, buffer: string | ArrayBuffer, options: WriteOptions, + callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.writeSync, fd, buffer, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); +} + +function write(fd: number, buffer: string | ArrayBuffer, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.writeSync, fd, buffer); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); +} + +function readSync(fd: number, buffer: ArrayBuffer, options?: ReadOptions): number { + return FileIoImpl.readSync(fd, buffer, options) +} + +function read(fd: number, buffer: ArrayBuffer, options?: ReadOptions): Promise { + return new Promise((resolve: (result: number) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute((fd: number, buffer: ArrayBuffer): number => { + return FileIoImpl.readSync(fd, buffer); + }, fd, buffer); + promise.then((ret: NullishType) => { + let result = ret as number; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((fd: number, buffer: ArrayBuffer, options: ReadOptions): number => { + return FileIoImpl.readSync(fd, buffer, options) + }, fd, buffer, options); + promise.then((ret: NullishType) => { + let result = ret as number; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function read(fd: number, buffer: ArrayBuffer, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.readSync, fd, buffer); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); +} + +function read(fd: number, buffer: ArrayBuffer, options: ReadOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.readSync, fd, buffer, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); +} + +function readLinesSync(filePath: string, options?: Options): ReaderIterator { + return FileIoImpl.readlinesSync(filePath, options) +} + +function readLines(filePath: string, options?: Options): Promise { + return new Promise((resolve: (result: ReaderIterator) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(FileIoImpl.readlinesSync, filePath); + promise.then((ret: NullishType): void => { + let it = ret as ReaderIterator; + resolve(it); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(FileIoImpl.readlinesSync, filePath, options); + promise.then((ret: NullishType): void => { + let it = ret as ReaderIterator; + resolve(it); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function readLines(filePath: string, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.readlinesSync, filePath); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let it = ret as ReaderIterator; + callback(e, it); + }).catch((e: BusinessError): void => { + let r: ReaderIterator = new ReaderIteratorInner(0); + callback(e, r); + }); +} + +function readLines(filePath: string, options: Options, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.readlinesSync, filePath, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let it = ret as ReaderIterator; + callback(e, it); + }).catch((e: BusinessError): void => { + let r: ReaderIterator = new ReaderIteratorInner(0); + callback(e, r); + }); +} + +function rmdirSync(path: string): void { + return FileIoImpl.rmdirSync(path) +} + +function rmdir(path: string): Promise { + return new Promise((resolve: (result: undefined) => void, + reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string): void => FileIoImpl.rmdirSync(path), path); + promise.then((ret: NullishType) => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function rmdir(path: string, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string): void => FileIoImpl.rmdirSync(path), path); + promise.then((ret: NullishType) => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function truncateSync(file: string | number, len?: number): void { + return FileIoImpl.truncateSync(file, len) +} + +function truncate(file: string | number, len?: number): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + if (len === undefined) { + let promise = taskpool.execute((file: string | number): undefined => { + return FileIoImpl.truncateSync(file); + }, file); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((file: string | number, len: number): undefined => { + return FileIoImpl.truncateSync(file, len); + }, file, len); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }) +} + +function truncate(file: string | number, callback: AsyncCallback): void { + let promise = taskpool.execute((file: string | number): undefined => { + return FileIoImpl.truncateSync(file); + }, file); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function truncate(file: string | number, len: number, callback: AsyncCallback): void { + let promise = taskpool.execute((file: string | number, len: number): undefined => { + return FileIoImpl.truncateSync(file, len); + }, file, len); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function unlinkSync(path: string): void { + return FileIoImpl.unlinkSync(path) +} + +function unlink(path: string): Promise { + return new Promise((resolve: (result: undefined) => void, + reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string): undefined => unlinkSync(path), path); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function unlink(path: string, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string): undefined => unlinkSync(path), path); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function readText(filePath: string, options?: ReadTextOptions): Promise { + return new Promise((resolve: (result: string) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(FileIoImpl.readTextSync, filePath); + promise.then((ret: NullishType): void => { + let r = ret as string; + resolve(r); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(FileIoImpl.readTextSync, filePath, options); + promise.then((ret: NullishType): void => { + let r = ret as string; + resolve(r); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function readText(filePath: string, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.readTextSync, filePath); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let r = ret as string; + callback(e, r); + }).catch((e: BusinessError): void => { + callback(e, ""); + }); +} + +function readText(filePath: string, options: ReadTextOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.readTextSync, filePath, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let r = ret as string; + callback(e, r); + }).catch((e: BusinessError): void => { + callback(e, ""); + }); +} + +function readTextSync(filePath: string, options?: ReadTextOptions): string { + return FileIoImpl.readTextSync(filePath, options); +} + +function listFile(path: string, options?: ListFileOptions): Promise { + return new Promise((resolve: (result: string[]) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(FileIoImpl.listFileSync, path); + promise.then((ret: NullishType): void => { + let r = ret as string[]; + resolve(r); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(FileIoImpl.listFileSync, path, options); + promise.then((ret: NullishType): void => { + let r = ret as string[]; + resolve(r); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function listFile(path: string, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.listFileSync, path); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let r = ret as string[]; + callback(e, r); + }).catch((e: BusinessError): void => { + callback(e, []); + }); +} + +function listFile(path: string, options: ListFileOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.listFileSync, path, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let r = ret as string[]; + callback(e, r); + }).catch((e: BusinessError): void => { + callback(e, []); + }); +} + +function listFileSync(path: string, options?: ListFileOptions): string[] { + return FileIoImpl.listFileSync(path, options); +} + +function copyFileSync(src: string | number, dest: string | number, mode?: number): void { + return FileIoImpl.copyFileSync(src, dest, mode) +} + +function statSync(file: string | number): Stat { + return FileIoImpl.statSync(file) +} + +function stat(file: string | number): Promise { + return new Promise((resolve: (result: Stat) => void, reject: (e: BusinessError) => void) => { + let promise = taskpool.execute(FileIoImpl.statSync, file); + promise.then((ret: NullishType): void => { + let r = ret as Stat; + resolve(r); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function stat(file: string | number, callback: AsyncCallback): void { + let p = taskpool.execute(FileIoImpl.statSync, file); + p.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let r = ret as Stat; + callback(e, r); + }).catch((e: BusinessError): void => { + callback(e, new StatInner(0)); + }); +} + +function fsyncSync(fd: number): void { + return FileIoImpl.fsyncSync(fd); +} + +function fsync(fd: number): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((fd: number): undefined => { + return FileIoImpl.fsyncSync(fd); + }, fd); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function symlinkSync(target: string, srcPath: string): void { + return FileIoImpl.symlinkSync(target, srcPath); +} + +function symlink(target: string, srcPath: string): Promise { + return new Promise((resolve: (result: undefined) => void, + reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((target: string, srcPath: string): undefined => { + return FileIoImpl.symlinkSync(target, srcPath); + }, target, srcPath); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} +function renameSync(oldPath: string, newPath: string): void { + return FileIoImpl.renameSync(oldPath, newPath); +} + +function rename(oldPath: string, newPath: string): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((oldPath: string, newPath: string): undefined => { + return FileIoImpl.renameSync(oldPath, newPath); + }, oldPath, newPath); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} +function createRandomAccessFileSync(file: string | File, mode?: number, + options?: RandomAccessFileOptions): RandomAccessFile { + return FileIoImpl.createRandomAccessFileSync(file, mode, options); +} + +function createRandomAccessFile(file: string | File, mode?: number, + options?: RandomAccessFileOptions): Promise { + return new Promise((resolve: (result: RandomAccessFile) => void, + reject: (e: BusinessError) => void) => { + if (mode === undefined) { + let promise = taskpool.execute(FileIoImpl.createRandomAccessFileSync, file); + promise.then((ret: NullishType): void => { + let raffile = ret as RandomAccessFileInner; + resolve(raffile); + }).catch((e: BusinessError): void => { + reject(e); + }); + return; + } + if (mode !== undefined && options === undefined) { + let promise = taskpool.execute(FileIoImpl.createRandomAccessFileSync, file, mode); + promise.then((ret: NullishType): void => { + let raffile = ret as RandomAccessFileInner; + resolve(raffile); + }).catch((e: BusinessError): void => { + reject(e); + }); + return; + } + let promise = taskpool.execute(FileIoImpl.createRandomAccessFileSync, file, mode, options); + promise.then((ret: NullishType): void => { + let raffile = ret as RandomAccessFileInner; + resolve(raffile); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} +function fdopenStream(fd: number, mode: string): Promise{ + return new Promise((resolve: (result: Stream) => void, reject: (e: BusinessError) => void) => { + let promise = taskpool.execute(FileIoImpl.fdopenStreamSync, fd, mode); + promise.then((ret: NullishType): void => { + let stream = ret as Stream; + resolve(stream); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function setxattrSync(path: string, key: string, value: string): void { + return FileIoImpl.setxattrSync(path, key, value) +} + +function setxattr(path: string, key: string, value: string): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string, key: string, value: string): undefined => + FileIoImpl.setxattrSync(path, key, value), path, key, value); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e as BusinessError); + }); + }); +} + +function createRandomAccessFile(file: string | File, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.createRandomAccessFileSync, file); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let raffile = ret as RandomAccessFile; + callback(e, raffile); + }).catch((e: BusinessError): void => { + let f: RandomAccessFile = new RandomAccessFileInner(0); + callback(e, f); + }); +} + +function createRandomAccessFile(file: string | File, mode: number, + callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.createRandomAccessFileSync, file, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let raffile = ret as RandomAccessFile; + callback(e, raffile); + }).catch((e: BusinessError): void => { + let f: RandomAccessFile = new RandomAccessFileInner(0); + callback(e, f); + }); +} + +function fdopenStream(fd: number, mode: string, callback: AsyncCallback): void { + let promise = taskpool.execute(FileIoImpl.fdopenStreamSync, fd, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let stream = ret as Stream; + callback(e, stream); + }).catch((e: BusinessError): void => { + let r: Stream = new StreamInner(0); + callback(e, r); + }); +} + +function fdopenStreamSync(fd: number, mode: string): Stream { + return FileIoImpl.fdopenStreamSync(fd, mode); +} + +function createStream(path: string, mode: string): Promise { + return new Promise((resolve: (result: Stream) => void, reject: (e: BusinessError) => void) => { + let promise = taskpool.execute(FileIoImpl.createStreamSync, path, mode); + promise.then((ret: NullishType): void => { + let stream = ret as Stream; + resolve(stream); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function createStream(path: string, mode: string, callback: AsyncCallback): void{ + let promise = taskpool.execute(FileIoImpl.createStreamSync, path, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let stream = ret as Stream; + callback(e, stream); + }).catch((e: BusinessError): void => { + let r: Stream = new StreamInner(0); + callback(e, r); + }); +} + +function createStreamSync(path: string, mode: string): Stream{ + return FileIoImpl.createStreamSync(path, mode); +} +function createReadStream(path: string, options?: ReadStreamOptions): ReadStream { + return new ReadStream(path, options) +} + +function createWriteStream(path: string, options?: WriteStreamOptions): WriteStream { + return new WriteStream(path, options); +} + + +function symlink(target: string, srcPath: string, callback: AsyncCallback): void { + let promise = taskpool.execute((target: string, srcPath: string): undefined => { + return FileIoImpl.symlinkSync(target, srcPath); + }, target, srcPath); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function utimes(path: string, mtime: number): void { + return FileIoImpl.utimes(path, mtime); +} + +function lstatSync(path: string): Stat { + return FileIoImpl.lstatSync(path) +} + +function lstat(path: string): Promise { + return new Promise((resolve: (result: Stat) => void, reject: (e: BusinessError) => void) => { + let promise = taskpool.execute(FileIoImpl.lstatSync, path); + promise.then((ret: NullishType): void => { + if (ret === null || ret === undefined) { + let e = new BusinessError(); + e.code = -1; + reject(e); + } else { + let r = ret as Stat; + resolve(r); + } + }).catch((e: BusinessError): void => { + reject(e); + }); + }); +} + +function lstat(path: string, callback: AsyncCallback): void { + let p = taskpool.execute(FileIoImpl.lstatSync, path); + p.then((ret: NullishType): void => { + let e = new BusinessError(); + if (ret === null || ret === undefined) { + e.code = -1; + let stat: Stat = new StatInner(0); + callback(e, stat); + } else { + e.code = 0; + let r = ret as Stat; + callback(e, r); + } + }).catch((e: BusinessError): void => { + callback(e, new StatInner(0)); + }); +} +function copyFile(src: string | number, dest: string | number, mode?: number): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + if (mode === undefined) { + let promise = taskpool.execute((src: string | number, dest: string | number): undefined => + FileIoImpl.copyFileSync(src, dest), src, dest); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((src: string | number, dest: string | number, mode: number): undefined => + FileIoImpl.copyFileSync(src, dest, mode), src, dest, mode); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function copy(srcUri: string, destUri: string, options?: CopyOptions): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + if (options === undefined) { + let promise = taskpool.execute((srcUri: string, destUri: string): undefined => + FileIoImpl.copySync(srcUri, destUri), srcUri, destUri); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((src: string | number, dest: string | number, mode: number): undefined => + FileIoImpl.copyFileSync(src, dest, mode), src, dest, mode); + let promise = taskpool.execute((srcUri: string, destUri: string, options: CopyOptions): undefined => + FileIoImpl.copySync(srcUri, destUri, options), srcUri, destUri, options); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); +} + +function copyFile(src: string | number, dest: string | number, mode: number, callback: AsyncCallback): void { + let promise = taskpool.execute((src: string | number, dest: string | number, mode: number): undefined => + FileIoImpl.copyFileSync(src, dest, mode), src, dest, mode); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function copy(srcUri: string, destUri: string, options: CopyOptions, callback: AsyncCallback): void { + let promise = taskpool.execute((srcUri: string, destUri: string, options: CopyOptions): undefined => + FileIoImpl.copySync(srcUri, destUri, options), srcUri, destUri, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function copyFile(src: string | number, dest: string | number, callback: AsyncCallback): void { + let promise = taskpool.execute((src: string | number, dest: string | number): undefined => + FileIoImpl.copyFileSync(src, dest), src, dest); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function copy(srcUri: string, destUri: string, callback: AsyncCallback): void { + let promise = taskpool.execute((srcUri: string, destUri: string): undefined => + FileIoImpl.copySync(srcUri, destUri), srcUri, destUri); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); +} + +function lseek(fd: number, offset: number, whence?: WhenceType): number { + return FileIoImpl.lseekSync(fd, offset, whence); +} + +export interface Filter { + suffix?: Array; + displayName?: Array; + mimeType?: Array; + fileSizeOver?: number; + lastModifiedAfter?: number; + excludeMedia?: boolean; +} + +export interface ListFileOptions { + recursion?: boolean; + listNum?: number; + filter?: Filter; +} + +export interface Options { + encoding?: string; +} + +export interface ReadOptions { + offset?: number; + length?: number; +} + +export interface ReadTextOptions extends ReadOptions { + encoding?: string; +} + +export interface Options { + encoding?: string; +} + +export interface WriteOptions extends Options { + offset?: number; + length?: number; +} + +export interface RandomAccessFileOptions { + start?: number; + end?: number; +} + +export interface Progress { + processedSize: number; + totalSize: number; +} + +class ProgressInner implements Progress { + processedSize: number; + totalSize: number; + + constructor(pSize: number, tSize: number) { + this.processedSize = pSize; + this.totalSize = tSize; + } +} + +export type ProgressListener = (progress: Progress) => void; + +export class TaskSignal { + private nativeTaskSignal: long = 0; + private native onCancelNative(): void; + private onCancelResolve: (path: string) => void; + private onCancelCallback(path: string): void { + if (this.onCancelResolve) { + this.onCancelResolve(path); + } + } + native cancel(): void; + onCancel(): Promise { + return new Promise((resolve: (path: string) => void, reject: (e: BusinessError) => void): void => { + this.onCancelResolve = resolve; + this.onCancelNative(); + }); + } +} + +export interface CopyOptions { + progressListener?: ProgressListener; + copySignal?: TaskSignal; +} + +enum AccessModeType { + EXIST = 0, + WRITE = 2, + READ = 4, + READ_WRITE = 6, +} + +enum AccessFlagType { + LOCAL = 0, +} + +export interface RandomAccessFile { + fd: number; + filePointer: number; + + setFilePointer(filePointer: number): void; + close(): void; + write(buffer: ArrayBuffer | string, options?: WriteOptions): Promise; + write(buffer: ArrayBuffer | string, callback: AsyncCallback): void; + write(buffer: ArrayBuffer | string, options: WriteOptions, callback: AsyncCallback): void; + writeSync(buffer: ArrayBuffer | string, options?: WriteOptions): number; + read(buffer: ArrayBuffer, options?: ReadOptions): Promise; + read(buffer: ArrayBuffer, callback: AsyncCallback): void; + read(buffer: ArrayBuffer, options: ReadOptions, callback: AsyncCallback): void; + readSync(buffer: ArrayBuffer, options?: ReadOptions): number; +} + +class RandomAccessFileInner implements RandomAccessFile { + fd: number = -1; + filePointer: number = -1; + + private nativePtr: long = 0; + + constructor(ptr: long) { + if (this.nativePtr === 0) { + this.nativePtr = ptr; + } + } + + setFilePointer(filePointer: number): void { + this.setFilePointer0(filePointer); + this.filePointer = filePointer; + } + + native setFilePointer0(filePointer: number): void; + + native close(): void; + + writeSync(buffer: ArrayBuffer | string, options?: WriteOptions): number { + let length = options? this.writeSync0(buffer, options) : this.writeSync0(buffer); + this.filePointer += length; + return length; + } + + native writeSync0(buffer: ArrayBuffer | string, options?: WriteOptions): number; + + write(buffer: ArrayBuffer | string, options?: WriteOptions): Promise { + return new Promise((resolve: (result: number) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(this.writeSync, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(this.writeSync, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); + } + + write(buffer: ArrayBuffer | string, options: WriteOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(this.writeSync, buffer, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + write(buffer: ArrayBuffer | string, callback: AsyncCallback): void { + let promise = taskpool.execute(this.writeSync, buffer); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + readSync(buffer: ArrayBuffer, options?: ReadOptions): number { + const length = options? this.readSync0(buffer, options) : this.readSync0(buffer); + this.filePointer += length; + return length; + } + + native readSync0(buffer: ArrayBuffer, options?: ReadOptions): number; + + read(buffer: ArrayBuffer, options?: ReadOptions): Promise { + return new Promise((resolve: (result: number) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(this.readSync, buffer); + promise.then((ret: NullishType): void => { + let result = ret as number; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(this.readSync, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number; + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); + } + + read(buffer: ArrayBuffer, options: ReadOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(this.readSync, buffer, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + read(buffer: ArrayBuffer, callback: AsyncCallback): void { + let promise = taskpool.execute(this.readSync, buffer); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } +} + +export interface File { + fd: number; + path: String; + name: String; + + getParent(): String; + lock(exclusive?: boolean): Promise; + lock(callback: AsyncCallback): void; + lock(exclusive: boolean, callback: AsyncCallback): void; + tryLock(exclusive?: boolean): void; + unlock(): void; +} + +class FileInner implements File { + fd: number = -1; + path: String = ""; + name: String = ""; + + private nativePtr: long = 0; + + constructor(ptr: long) { + if (this.nativePtr === 0) { + this.nativePtr = ptr; + } + } + + native getParent(): String; + native lockSync(exclusive?: boolean): void; + + lock(exclusive?: boolean): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + if (exclusive === undefined) { + let promise = taskpool.execute((): undefined => { + return this.lockSync(); + }); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute((exclusive: boolean): undefined => { + return this.lockSync(exclusive); + }, exclusive); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); + } + + lock(callback: AsyncCallback): void { + let promise = taskpool.execute((): undefined => { + return this.lockSync(); + }); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); + } + + lock(exclusive: boolean, callback: AsyncCallback): void { + let promise = taskpool.execute((exclusive: boolean): undefined => { + return this.lockSync(exclusive); + }, exclusive); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); + } + + native tryLock(exclusive?: boolean): void; + native unlock(): void; + +} + +enum LocationType { + LOCAL = 1, + CLOUD = 2 +} + +export interface ReaderIteratorResult { + done: boolean; + value: string; +} + +class ReaderIteratorResultInner implements ReaderIteratorResult { + private nativePtr: long = 0; + + constructor(ptr: long) { + if (this.nativePtr === 0) { + this.nativePtr = ptr; + } + } + + done: boolean = false; + value: string = ""; +} + +export interface ReaderIterator { + next(): ReaderIteratorResult; +} + +class ReaderIteratorInner implements ReaderIterator { + private nativePtr: long = 0; + + constructor(ptr: long) { + if (this.nativePtr === 0) { + this.nativePtr = ptr; + } + } + + native next(): ReaderIteratorResult; +} + +export interface Stat { + ino: bigint; + mode: number; + uid: number; + gid: number; + size: number; + atime: number; + mtime: number; + ctime: number; + atimeNs: bigint; + mtimeNs: bigint; + ctimeNs: bigint; + location: LocationType; + + isBlockDevice(): boolean; + isCharacterDevice(): boolean; + isDirectory(): boolean; + isFIFO(): boolean; + isFile(): boolean; + isSocket(): boolean; + isSymbolicLink(): boolean; +} + +class StatInner implements Stat { + ino: bigint = 0n; + mode: number; + uid: number; + gid: number; + size: number; + atime: number; + mtime: number; + ctime: number; + atimeNs: bigint = 0n; + mtimeNs: bigint = 0n; + ctimeNs: bigint = 0n; + location: LocationType = LocationType.LOCAL; + + private nativeStat: long = 0; + + constructor(stat: long) { + if (this.nativeStat === 0) { + this.nativeStat = stat; + } + } + + native isBlockDevice(): boolean; + native isCharacterDevice(): boolean; + native isDirectory(): boolean; + native isFIFO(): boolean; + native isFile(): boolean; + native isSocket(): boolean; + native isSymbolicLink(): boolean; +} + +export interface Stream { + close(): Promise; + close(callback: AsyncCallback): void; + closeSync(): void; + flush(): Promise; + flush(callback: AsyncCallback): void; + flushSync(): void; + write(buffer: ArrayBuffer | string, options?: WriteOptions): Promise; + write(buffer: ArrayBuffer | string, callback: AsyncCallback): void; + write(buffer: ArrayBuffer | string, options: WriteOptions, callback: AsyncCallback): void; + writeSync(buffer: ArrayBuffer | string, options?: WriteOptions): number; + read(buffer: ArrayBuffer, options?: ReadOptions): Promise; + read(buffer: ArrayBuffer, callback: AsyncCallback): void; + read(buffer: ArrayBuffer, options: ReadOptions, callback: AsyncCallback): void; + readSync(buffer: ArrayBuffer, options?: ReadOptions): number; + seek(offset: number, whence?: number): number; +} + +class StreamInner implements Stream { + private nativePtr: long = 0; + + constructor(ptr: long) { + if (this.nativePtr === 0) { + this.nativePtr = ptr; + } + } + + close(): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((): undefined => this.closeSync()); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); + } + + close(callback: AsyncCallback): void { + let promise = taskpool.execute((): undefined => this.closeSync()); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); + } + + native closeSync(): void; + + flush(): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((): undefined => this.flushSync()); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); + } + + flush(callback: AsyncCallback): void { + let promise = taskpool.execute((): undefined => this.flushSync()); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); + } + + native flushSync(): void; + + write(buffer: ArrayBuffer | string, options?: WriteOptions): Promise { + return new Promise((resolve: (result: number) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(this.writeSync, buffer); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(this.writeSync, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); + } + + write(buffer: ArrayBuffer | string, callback: AsyncCallback): void { + let promise = taskpool.execute(this.writeSync, buffer); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + write(buffer: ArrayBuffer | string, options: WriteOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(this.writeSync, buffer, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + native writeSync(buffer: ArrayBuffer | string, options?: WriteOptions): number; + + read(buffer: ArrayBuffer, options?: ReadOptions): Promise { + return new Promise((resolve: (result: number) => void, reject: (e: BusinessError) => void) => { + if (options === undefined) { + let promise = taskpool.execute(this.readSync, buffer); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } else { + let promise = taskpool.execute(this.readSync, buffer, options); + promise.then((ret: NullishType): void => { + let result = ret as number + resolve(result); + }).catch((e: BusinessError): void => { + reject(e); + }); + } + }); + } + + read(buffer: ArrayBuffer, callback: AsyncCallback): void { + let promise = taskpool.execute(this.readSync, buffer); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + read(buffer: ArrayBuffer, options: ReadOptions, callback: AsyncCallback): void { + let promise = taskpool.execute(this.readSync, buffer, options); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let result = ret as number; + callback(e, result); + }).catch((e: BusinessError): void => { + callback(e, 0); + }); + } + + native readSync(buffer: ArrayBuffer, options?: ReadOptions): number; + native seek(offset: number, whence?: number): number; +} + +enum OpenMode { + READ_ONLY = 0o0, + WRITE_ONLY = 0o1, + READ_WRITE = 0o2, + CREATE = 0o100, + TRUNC = 0o1000, + APPEND = 0o2000, + NONBLOCK = 0o4000, + DIR = 0o200000, + NOFOLLOW = 0o400000, + SYNC = 0o4010000, +} + +enum WhenceType { + SEEK_SET = 0, + SEEK_CUR = 1, + SEEK_END = 2, +} + +export interface ReadStreamOptions { + start?: number; + end?: number; +} + +export interface WriteStreamOptions { + mode?: number; + start?: number; +} + +export class ReadStream extends stream.Readable { + private pathInner: string; + private bytesReadInner: number; + private offset: number; + private start?: number; + private end?: number; + private stream?: Stream; + + constructor(path: string, options?: ReadStreamOptions) { + super(); + this.pathInner = path; + this.bytesReadInner = 0; + this.start = options?.start; + this.end = options?.end; + this.stream = createStreamSync(this.pathInner, 'r'); + this.offset = this.start ?? 0; + } + + get path(): string { + return this.pathInner; + } + + get bytesRead(): number { + return this.bytesReadInner; + } + + seek(offset: number, whence?: WhenceType): number { + if (whence === undefined) { + let off = this.stream?.seek(offset); + if (off !== undefined) { + this.offset = off + } + } else { + let off = this.stream?.seek(offset, whence); + if (off !== undefined) { + this.offset = off + } + } + return this.offset; + } + + close(): void { + this.stream?.close(); + } + + doInitialize(callback: () => void): void { + callback(); + } + + doRead(size: number): void { + let readSize = size; + let end = this.end + if (end !== undefined) { + if (this.offset > end) { + this.push(null); + return; + } + if (this.offset + readSize > end) { + readSize = end - this.offset; + } + } + let buffer = new ArrayBuffer(readSize); + const off = this.offset; + this.offset += readSize; + this.stream?.read(buffer, { offset: off, length: readSize }) + .then((readOut: number) => { + if (readOut > 0) { + this.bytesReadInner += readOut; + this.push(new Uint8Array(buffer.slice(0, readOut))); + } + if (readOut !== readSize || readOut < size) { + this.offset = this.offset - readSize + readOut; + this.push(null); + } + }); + } +} + +export class WriteStream extends stream.Writable { + private pathInner: string; + private bytesWrittenInner: number; + private offset: number; + private mode: string; + private start?: number; + private stream?: Stream; + + constructor(path: string, options?: WriteStreamOptions) { + super(); + this.pathInner = path; + this.bytesWrittenInner = 0; + this.start = options?.start; + this.mode = this.convertOpenMode(options?.mode); + this.stream = createStreamSync(this.pathInner, this.mode); + this.offset = this.start ?? 0; + } + + get path(): string { + return this.pathInner; + } + + get bytesWritten(): number { + return this.bytesWrittenInner; + } + + seek(offset: number, whence?: WhenceType): number { + if (whence === undefined) { + let off = this.stream?.seek(offset); + if (off !== undefined) { + this.offset = off + } + } else { + let off = this.stream?.seek(offset, whence); + if (off !== undefined) { + this.offset = off + } + } + return this.offset; + } + + close(): void { + this.stream?.close(); + } + + doInitialize(callback: () => void): void { + callback(); + } + + doWrite(chunk: string | ArrayBuffer, encoding: string, callback: () => void): void { + this.stream?.write(chunk, { offset: this.offset }) + .then((writeIn: number) => { + this.offset += writeIn; + this.bytesWrittenInner += writeIn; + callback(); + }) + .finally(() => { + this.stream?.flush(); + }); + } + + convertOpenMode(mode?: number): string { + let modeStr = 'w'; + if (mode === undefined) { + return modeStr; + } + if ((mode as number) & OpenMode.WRITE_ONLY) { + modeStr = 'w'; + } + if ((mode as number) & OpenMode.READ_WRITE) { + modeStr = 'w+'; + } + if (((mode as number) & OpenMode.WRITE_ONLY) && ((mode as number) & OpenMode.APPEND)) { + modeStr = 'a'; + } + if (((mode as number) & OpenMode.READ_WRITE) && ((mode as number) & OpenMode.APPEND)) { + modeStr = 'a+'; + } + return modeStr; + } +} +enum WhenceType { + SEEK_SET = 0, + SEEK_CUR = 1, + SEEK_END = 2 +} + +class FileIoImpl { + + static { + loadLibrary("ani_fs_class"); + } + + static native doAccessSync(path: string, mode?: AccessModeType, flag?: AccessFlagType): boolean; + + static native closeSync(file: number | File): void; + + static native copySync(srcUri: string, destUri: string, options?: CopyOptions): void; + + static native copyFileSync(src: string | number, dest: string | number, mode?: number): void; + + static native fdatasyncSync(fd: number): void; + + static native getxattrSync(path: string, key: string): string; + + static native createStreamSync(path: string, mode: string): Stream; + + static native fdopenStreamSync(fd: number, mode: string): Stream; + + static native dup(fd: number): File; + + static native listFileSync(path: string, options?: ListFileOptions): string[]; + + static native lstatSync(path: string): Stat; + + static native lseekSync(fd: number, offset: number, whence?: WhenceType): number; + + static native mkdirSync(path: string): void; + + static native mkdirSync(path: string, recursion: boolean): void; + + static native movedirSync(src: string, dest: string, mode?: number): void; + + static native mkdtempSync(prefix: string): string; + + static native moveFileSync(src: String, dest: String, mode?: number): void; + + static native openSync(path: String, mode?: number): File; + + static native readlinesSync(filePath: string, options?: Options): ReaderIterator; + + static native readSync(fd: number, buffer: ArrayBuffer, options?: ReadOptions): number; + + static native readTextSync(filePath: string, options?: ReadTextOptions): string; + + static native rmdirSync(path: string): void; + + static native setxattrSync(path: string, key: string, value: string): void; + + static native statSync(file: string | number): Stat; + + static native truncateSync(file: string | number, len?: number): void; + + static native unlinkSync(path: string): void; + + static native writeSync(fd: number, buffer: string | ArrayBuffer, options?: WriteOptions): number; + + static native fsyncSync(fd: number): void; + + static native renameSync(oldPath: string, newPath: string): void; + + static native createRandomAccessFileSync(file: string | File, mode?: number, + options?: RandomAccessFileOptions): RandomAccessFile; + + static native symlinkSync(target: string, srcPath: string): void; + + static native utimes(path: string, mtime: number): void; +} diff --git a/interfaces/kits/js/src/mod_fs/class_file/ani/file_ani.cpp b/interfaces/kits/js/src/mod_fs/class_file/ani/file_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6353d3941544bf0258ee0bb5d2f5dbc02b2bbba --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/ani/file_ani.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2025 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 "file_ani.h" + +#include "error_handler.h" +#include "file_wrapper.h" +#include "filemgmt_libhilog.h" +#include "fs_file.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +ani_string FileAni::GetParent(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsFile = FileWrapper::Unwrap(env, object); + if (fsFile == nullptr) { + HILOGE("Cannot unwrap fsfile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return {}; + } + auto ret = fsFile->GetParent(); + if (!ret.IsSuccess()) { + HILOGE("Cannot get file parent!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return {}; + } + auto value = ret.GetData().value(); + auto [succ, parent] = TypeConverter::ToAniString(env, value); + if (!succ) { + HILOGE("Cannot convert file parent to ani string!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return {}; + } + return parent; +} + +void FileAni::LockSync(ani_env *env, [[maybe_unused]] ani_object object, ani_object exclusive) +{ + ani_boolean isUndefined; + bool exc = false; + env->Reference_IsUndefined(exclusive, &isUndefined); + if (!isUndefined) { + exc = true; + } + auto fsFile = FileWrapper::Unwrap(env, object); + if (fsFile == nullptr) { + HILOGE("Cannot unwrap fsfile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = fsFile->Lock(exc); + if (!ret.IsSuccess()) { + HILOGE("Lock file failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void FileAni::TryLock(ani_env *env, [[maybe_unused]] ani_object object, ani_object exclusive) +{ + ani_boolean isUndefined; + bool exc = false; + env->Reference_IsUndefined(exclusive, &isUndefined); + if (!isUndefined) { + exc = true; + } + auto fsFile = FileWrapper::Unwrap(env, object); + if (fsFile == nullptr) { + HILOGE("Cannot unwrap fsfile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = fsFile->TryLock(exc); + if (!ret.IsSuccess()) { + HILOGE("TryLock file failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void FileAni::UnLock(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsFile = FileWrapper::Unwrap(env, object); + if (fsFile == nullptr) { + HILOGE("Cannot unwrap fsfile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = fsFile->UnLock(); + if (!ret.IsSuccess()) { + HILOGE("UnLock file failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/ani/file_ani.h b/interfaces/kits/js/src/mod_fs/class_file/ani/file_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..1ab5eb61ebbfd577ffba77ef23bf2839e1d7800e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/ani/file_ani.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 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_FILE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_FILE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class FileAni final { +public: + static ani_string GetParent(ani_env *env, [[maybe_unused]] ani_object object); + static void LockSync(ani_env *env, [[maybe_unused]] ani_object object, ani_object exclusive); + static void TryLock(ani_env *env, [[maybe_unused]] ani_object object, ani_object exclusive); + static void UnLock(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_FILE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/ani/file_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_file/ani/file_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..047f033a5bf60d0b18b3dd57db9e5bc21fb752ff --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/ani/file_wrapper.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 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 "file_wrapper.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fs_file.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +FsFile *FileWrapper::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsFile *file = reinterpret_cast(ptrValue); + return file; +} + +ani_object FileWrapper::Wrap(ani_env *env, const FsFile *file) +{ + static const char *className = "L@ohos/file/fs/FileInner;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "J:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(file)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", className); + return nullptr; + } + + const auto &fdRet = file->GetFD(); + if (!fdRet.IsSuccess()) { + HILOGE("GetFD Failed!"); + return nullptr; + } + + const auto &fd = fdRet.GetData().value(); + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "fd", static_cast(fd))) { + HILOGE("Set fd field value failed!"); + return nullptr; + } + + const auto &pathRet = file->GetPath(); + if (!pathRet.IsSuccess()) { + HILOGE("GetPath Failed!"); + return nullptr; + } + + const auto &path = pathRet.GetData().value(); + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "path", path)) { + HILOGE("Set path field value failed!"); + return nullptr; + } + + const auto &nameRet = file->GetName(); + if (!pathRet.IsSuccess()) { + HILOGE("GetPath Failed!"); + return nullptr; + } + + const auto &name = nameRet.GetData().value(); + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "name", name)) { + HILOGE("Set name field value failed!"); + return nullptr; + } + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/ani/file_wrapper.h b/interfaces/kits/js/src/mod_fs/class_file/ani/file_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..22bd957fe636ff584dfcdc43290aad4a74f179c8 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/ani/file_wrapper.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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_FILE_WRAPPER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_FILE_WRAPPER_H + +#include +#include "fs_file.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class FileWrapper final { +public: + static FsFile *Unwrap(ani_env *env, ani_object object); + static ani_object Wrap(ani_env *env, const FsFile *file); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_FILE_WRAPPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/file_instantiator.cpp b/interfaces/kits/js/src/mod_fs/class_file/file_instantiator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b68e9474ef51823005dc0df5c11cdcd41380e3dc --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/file_instantiator.cpp @@ -0,0 +1,82 @@ +/* +* Copyright (c) 2025 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 "file_instantiator.h" + +#include "file_entity.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::DistributedFS; + +FsResult FileInstantiator::InstantiateFile(int fd, string pathOrUri, bool isUri) +{ + FsResult result = FsFile::Constructor(); + if (!result.IsSuccess()) { + HILOGE("Failed to instantiate class"); + int ret = close(fd); + if (ret < 0) { + HILOGE("Failed to close fd"); + } + return FsResult::Error(EIO); + } + + const FsFile *objFile = result.GetData().value(); + if (!objFile) { + HILOGE("Failed to get fsFile"); + int ret = close(fd); + if (ret < 0) { + HILOGE("Failed to close fd"); + } + return FsResult::Error(EIO); + } + + auto *fileEntity = objFile->GetFileEntity(); + if (!fileEntity) { + HILOGE("Failed to get fileEntity"); + int ret = close(fd); + if (ret < 0) { + HILOGE("Failed to close fd"); + } + delete objFile; + objFile = nullptr; + return FsResult::Error(EIO); + } + auto fdg = CreateUniquePtr(fd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + close(fd); + delete objFile; + objFile = nullptr; + return FsResult::Error(ENOMEM); + } + fileEntity->fd_.swap(fdg); + if (isUri) { + fileEntity->path_ = ""; + fileEntity->uri_ = pathOrUri; + } else { + fileEntity->path_ = pathOrUri; + fileEntity->uri_ = ""; + } + return result; +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/file_instantiator.h b/interfaces/kits/js/src/mod_fs/class_file/file_instantiator.h new file mode 100644 index 0000000000000000000000000000000000000000..b711219ab7bb4e4fc8ec97a132e810017ae3a09f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/file_instantiator.h @@ -0,0 +1,35 @@ +/* +* Copyright (c) 2025 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_FILE_INSTANTIATOR_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_FILE_INSTANTIATOR_H + +#include "filemgmt_libfs.h" +#include "fs_file.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +class FileInstantiator { +public: + static FsResult InstantiateFile(int fd, string pathOrUri, bool isUri); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_FILE_INSTANTIATOR_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/fs_file.cpp b/interfaces/kits/js/src/mod_fs/class_file/fs_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae55f850400086afcda55fb50d7e702bf45b68ed --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/fs_file.cpp @@ -0,0 +1,197 @@ +/* +* Copyright (c) 2025 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 "fs_file.h" + +#include + +#include "file_uri.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +static tuple> RealPathCore(const string &srcPath) +{ + std::unique_ptr realpath_req = { new (std::nothrow) uv_fs_t, + FsUtils::FsReqCleanup }; + if (!realpath_req) { + HILOGE("Failed to request heap memory."); + return { ENOMEM, move(realpath_req) }; + } + int ret = uv_fs_realpath(nullptr, realpath_req.get(), srcPath.c_str(), nullptr); + return { ret, move(realpath_req) }; +} + +FsResult FsFile::GetFD() const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + return FsResult::Success(fileEntity->fd_.get()->GetFD()); +} + +FsResult FsFile::GetPath() const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + if (fileEntity->uri_.length() != 0) { + AppFileService::ModuleFileUri::FileUri fileUri(fileEntity->uri_); + return FsResult::Success(fileUri.GetPath()); + } + auto [realPathRes, realPath] = RealPathCore(fileEntity->path_); + if (realPathRes != ERRNO_NOERR) { + HILOGE("Failed to get real path"); + return FsResult::Error(realPathRes); + } + return FsResult::Success(string(static_cast(realPath->ptr))); +} + +FsResult FsFile::GetName() const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + if (fileEntity->uri_.length() != 0) { + AppFileService::ModuleFileUri::FileUri fileUri(fileEntity->uri_); + return FsResult::Success(fileUri.GetName()); + } + auto [realPathRes, realPath] = RealPathCore(fileEntity->path_); + if (realPathRes != ERRNO_NOERR) { + HILOGE("Failed to get real path"); + return FsResult::Error(realPathRes); + } + string path(static_cast(realPath->ptr)); + auto pos = path.find_last_of('/'); + if (pos == string::npos) { + HILOGE("Failed to split filename from path"); + return FsResult::Error(ENOENT); + } + return FsResult::Success(path.substr(pos + 1)); +} + +FsResult FsFile::GetParent() const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + + string path(fileEntity->path_); + if (fileEntity->uri_.length() != 0) { + AppFileService::ModuleFileUri::FileUri fileUri(fileEntity->uri_); + path = fileUri.GetPath(); + } else { + auto [realPathRes, realPath] = RealPathCore(path); + if (realPathRes) { + HILOGE("Failed to get real path"); + return FsResult::Error(realPathRes); + } + path = static_cast(realPath->ptr); + } + auto pos = path.find_last_of('/'); + if (pos == string::npos) { + HILOGE("Failed to split filename from path"); + return FsResult::Error(ENOENT); + } + return FsResult::Success(path.substr(0, pos)); +} + +FsResult FsFile::Lock(bool exclusive) const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + + if (!fileEntity || !fileEntity->fd_.get()) { + HILOGE("File has been closed in Lock cbExec possibly"); + return FsResult::Error(EIO); + } + int ret = 0; + auto mode = exclusive ? LOCK_EX : LOCK_SH; + ret = flock(fileEntity->fd_.get()->GetFD(), mode); + if (ret < 0) { + HILOGE("Failed to lock file"); + return FsResult::Error(errno); + } else { + return FsResult::Success(); + } +} + +FsResult FsFile::TryLock(bool exclusive) const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + + int ret = 0; + auto mode = exclusive ? LOCK_EX : LOCK_SH; + ret = flock(fileEntity->fd_.get()->GetFD(), mode | LOCK_NB); + if (ret < 0) { + HILOGE("Failed to try to lock file"); + return FsResult::Error(errno); + } + + return FsResult::Success(); +} + +FsResult FsFile::UnLock() const +{ + if (!fileEntity) { + HILOGE("Failed to get file entity"); + return FsResult::Error(EINVAL); + } + + int ret = 0; + ret = flock(fileEntity->fd_.get()->GetFD(), LOCK_UN); + if (ret < 0) { + HILOGE("Failed to unlock file"); + return FsResult::Error(errno); + } + return FsResult::Success(); +} +#endif + +FsResult FsFile::Constructor() +{ + auto rafEntity = CreateUniquePtr(); + if (rafEntity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + FsFile *fsFilePtr = new FsFile(move(rafEntity)); + + if (fsFilePtr == nullptr) { + HILOGE("Failed to create FsFile object on heap."); + return FsResult::Error(ENOMEM); + } + + return FsResult::Success(move(fsFilePtr)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_file/fs_file.h b/interfaces/kits/js/src/mod_fs/class_file/fs_file.h new file mode 100644 index 0000000000000000000000000000000000000000..dbdd471bf7d664f5e0ec948b94733751f3694a95 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_file/fs_file.h @@ -0,0 +1,75 @@ +/* +* Copyright (c) 2025 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_FILE_FS_FILE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_FILE_FS_FILE_H + +#include "file_entity.h" +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +class FsFile { +public: + inline static const string className_ = "File"; + + FileEntity *GetFileEntity() const + { + return fileEntity.get(); + } + + FsFile(const FsFile &other) = delete; + FsFile &operator=(const FsFile &other) = delete; + + FsFile(FsFile &&other) noexcept : fileEntity(move(other.fileEntity)) + { + other.fileEntity = nullptr; + } + + FsFile &operator=(FsFile &&other) noexcept + { + if (this != &other) { + fileEntity = move(other.fileEntity); + other.fileEntity = nullptr; + } + return *this; + } + + ~FsFile() = default; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + FsResult GetPath() const; + FsResult GetName() const; + FsResult GetParent() const; + FsResult Lock(bool exclusive = false) const; + FsResult TryLock(bool exclusive = false) const; + FsResult UnLock() const; +#endif + static FsResult Constructor(); + FsResult GetFD() const; + +private: + unique_ptr fileEntity; + explicit FsFile(unique_ptr entity) : fileEntity(move(entity)) {} +}; + +const string PROCEDURE_LOCK_NAME = "FileIOFileLock"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_FILE_FS_FILE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..36f30dad896fd81b72a4be4e7e80c0d242281c88 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2025 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_ani.h" + +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fs_randomaccessfile.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +static FsRandomAccessFile *Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap FsRandomAccessFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsRandomAccessFile *rafFile = reinterpret_cast(ptrValue); + return rafFile; +} + +static tuple> ToReadOptions(ani_env *env, ani_object obj) +{ + ReadOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + return { true, make_optional(move(options)) }; +} + +static tuple> ToWriteOptions(ani_env *env, ani_object obj) +{ + WriteOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding; + return { true, make_optional(move(options)) }; +} + +static tuple ParseStringBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + env->FindClass("Lstd/core/String;", &cls); + + ani_boolean isString; + env->Object_InstanceOf(buf, cls, &isString); + if (!isString) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, move(result) }; +} + +static tuple ParseArrayBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + env->FindClass("Lescompat/ArrayBuffer;", &cls); + + ani_boolean isArrayBuffer; + env->Object_InstanceOf(buf, cls, &isArrayBuffer); + if (!isArrayBuffer) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, move(result) }; +} + +void RandomAccessFileAni::SetFilePointer(ani_env *env, [[maybe_unused]] ani_object object, ani_double fp) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = rafFile->SetFilePointerSync(static_cast(fp)); + if (!ret.IsSuccess()) { + HILOGE("SetFilePointerSync failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void RandomAccessFileAni::Close(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + auto ret = rafFile->CloseSync(); + if (!ret.IsSuccess()) { + HILOGE("close rafFile failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +ani_double RandomAccessFileAni::WriteSync(ani_env *env, [[maybe_unused]] ani_object object, + ani_object buf, ani_object options) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return -1; + } + + auto [succOp, op] = ToWriteOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [isString, stringBuffer] = ParseStringBuffer(env, buf); + if (isString) { + auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer); + if (!succBuf) { + HILOGE("Failed to resolve stringBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = rafFile->WriteSync(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + ErrorHandler::Throw(env, ret.GetError()); + return -1; + } + return static_cast(ret.GetData().value()); + } + + auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf); + if (isArrayBuffer) { + auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = rafFile->WriteSync(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + ErrorHandler::Throw(env, ret.GetError()); + return -1; + } + return static_cast(ret.GetData().value()); + } + HILOGE("Unsupported buffer type!"); + ErrorHandler::Throw(env, EINVAL); + return -1; +} + +ani_double RandomAccessFileAni::ReadSync(ani_env *env, [[maybe_unused]] ani_object object, + ani_arraybuffer buf, ani_object options) +{ + auto rafFile = Unwrap(env, object); + if (rafFile == nullptr) { + HILOGE("Cannot unwrap rafFile!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return -1; + } + + auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buf); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succOp, op] = ToReadOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = rafFile-> ReadSync(arrayBuffer, op); + if (!ret.IsSuccess()) { + HILOGE("Read file content failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.h b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..7fc783bd5e2c902aa87a9f3d7270d318e3d79829 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/ani/randomaccessfile_ani.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 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_ANI_RANDOMACCESSFILE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_ANI_RANDOMACCESSFILE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class RandomAccessFileAni final { +public: + static void SetFilePointer(ani_env *env, [[maybe_unused]] ani_object object, ani_double fp); + static void Close(ani_env *env, [[maybe_unused]] ani_object object); + static ani_double WriteSync(ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options); + static ani_double ReadSync(ani_env *env, [[maybe_unused]] ani_object object, + ani_arraybuffer buf, ani_object options); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif //INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_ANI_RANDOMACCESSFILE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/fs_randomaccessfile.cpp b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/fs_randomaccessfile.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87e48b46921fad99f0bc7680a3d455777e6bdfe1 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/fs_randomaccessfile.cpp @@ -0,0 +1,287 @@ +/* +* Copyright (c) 2025 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 "fs_randomaccessfile.h" + +#include + +#include "file_uri.h" +#include "file_utils.h" +#include "filemgmt_libfs.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static int DoReadRAF(void* buf, size_t len, int fd, int64_t offset) +{ + unique_ptr readReq = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (readReq == 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, readReq.get(), fd, &iov, 1, offset, nullptr); + return ret; +} + +static int DoWriteRAF(void* buf, size_t len, int fd, int64_t offset) +{ + unique_ptr writeReq = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (writeReq == 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, writeReq.get(), fd, &iov, 1, offset, nullptr); + return ret; +} + +FsResult FsRandomAccessFile::GetFD() const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + return FsResult::Success(rafEntity->fd.get()->GetFD()); +} + +FsResult FsRandomAccessFile::GetFPointer() const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + return FsResult::Success(rafEntity->filePointer); +} + +FsResult FsRandomAccessFile::SetFilePointerSync(const int64_t &fp) const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + rafEntity->filePointer = fp; + return FsResult::Success(); +} + +static int64_t CalculateOffset(int64_t offset, int64_t fPointer) +{ + if (offset < 0) { + HILOGD("No specified offset provided"); + offset = fPointer; + } else { + offset += fPointer; + } + return offset; +} + +tuple ValidReadArg(ArrayBuffer &buffer, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + void *buf = buffer.buf; + size_t bufLen = buffer.length; + + if (bufLen > UINT_MAX) { + HILOGE("Invalid arraybuffer"); + return { false, nullptr, retLen, offset }; + } + optional lengthOp = nullopt; + optional offsetOp = nullopt; + if (options.has_value()) { + ReadOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + } + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, nullptr, retLen, offset }; + } + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, nullptr, retLen, offset }; + } + } + return { true, buf, retLen, offset }; +} + +FsResult FsRandomAccessFile::ReadSync(ArrayBuffer &buffer, const optional &options) const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + auto [succ, buf, len, offset] = ValidReadArg(buffer, options); + if (!succ) { + HILOGE("Invalid buffer/options"); + return FsResult::Error(EINVAL); + } + offset = CalculateOffset(offset, rafEntity->filePointer); + int actLen = DoReadRAF(buf, len, rafEntity->fd.get()->GetFD(), offset); + if (actLen < 0) { + HILOGE("Failed to read file for %{private}d", actLen); + return FsResult::Error(actLen); + } + rafEntity->filePointer = offset + actLen; + return FsResult::Success(static_cast(actLen)); +} + +tuple ValidWriteArg( + void *buffer, const size_t bufLen, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + + if (bufLen > UINT_MAX) { + HILOGE("The Size of buffer is too large"); + return { false, nullptr, 0, offset }; + } + + optional lengthOp = nullopt; + optional offsetOp = nullopt; + if (options.has_value()) { + WriteOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + } + + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, nullptr, 0, offset }; + } + + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, nullptr, 0, offset }; + } + } + return { true, buffer, retLen, offset }; +} + +FsResult FsRandomAccessFile::WriteSync(const string &buffer, const optional &options) const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + + bool succ = false; + size_t len = 0; + int64_t offset = -1; + void *buf = nullptr; + size_t bufLen = static_cast(buffer.length()); + + tie(succ, buf, len, offset) = ValidWriteArg(const_cast(static_cast(buffer.c_str())), + bufLen, options); + if (!succ) { + HILOGE("Invalid buffer/options"); + return FsResult::Error(EINVAL); + } + offset = CalculateOffset(offset, rafEntity->filePointer); + int writeLen = DoWriteRAF(buf, len, rafEntity->fd.get()->GetFD(), offset); + if (writeLen < 0) { + return FsResult::Error(writeLen); + } + rafEntity->filePointer = offset + writeLen; + return FsResult::Success(static_cast(writeLen)); +} + +FsResult FsRandomAccessFile::WriteSync(const ArrayBuffer &buffer, const optional &options) const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + + bool succ = false; + size_t len = 0; + int64_t offset = -1; + void *buf = nullptr; + + tie(succ, buf, len, offset) = ValidWriteArg(buffer.buf, buffer.length, options); + if (!succ) { + HILOGE("Invalid buffer/options"); + return FsResult::Error(EINVAL); + } + offset = CalculateOffset(offset, rafEntity->filePointer); + int writeLen = DoWriteRAF(buf, len, rafEntity->fd.get()->GetFD(), offset); + if (writeLen < 0) { + return FsResult::Error(writeLen); + } + rafEntity->filePointer = offset + writeLen; + return FsResult::Success(static_cast(writeLen)); +} + +static int CloseFd(int fd) +{ + unique_ptr closeReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!closeReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_close(nullptr, closeReq.get(), fd, nullptr); + if (ret < 0) { + HILOGE("Failed to close file with ret: %{private}d", ret); + return ret; + } + return ERRNO_NOERR; +} + +FsResult FsRandomAccessFile::CloseSync() const +{ + if (!rafEntity) { + HILOGE("Failed to get entity of RandomAccessFile"); + return FsResult::Error(EIO); + } + auto err = CloseFd(rafEntity->fd.get()->GetFD()); + if (err) { + return FsResult::Error(err); + } + return FsResult::Success(); +} + +FsResult FsRandomAccessFile::Constructor() +{ + auto rafEntity = CreateUniquePtr(); + if (rafEntity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + FsRandomAccessFile *randomAccessFilePtr = new FsRandomAccessFile(move(rafEntity)); + if (randomAccessFilePtr == nullptr) { + HILOGE("INNER BUG. Failed to wrap entity for obj RandomAccessFile"); + return FsResult::Error(EIO); + } + return FsResult::Success(move(randomAccessFilePtr)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/fs_randomaccessfile.h b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/fs_randomaccessfile.h new file mode 100644 index 0000000000000000000000000000000000000000..abeb9a02c48b45dab5a9ae92ab128b1ec92edcf2 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/fs_randomaccessfile.h @@ -0,0 +1,86 @@ +/* +* Copyright (c) 2025 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_FS_RANDOMACCESSFILE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_FS_RANDOMACCESSFILE_H + +#include "randomaccessfile_entity.h" +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct WriteOptions { + optional length = nullopt; + optional offset = nullopt; + optional encoding = nullopt; +}; + +struct ReadOptions { + optional offset = nullopt; + optional length = nullopt; +}; + +class FsRandomAccessFile { +public: + inline static const string className_ = "RandomAccessFile"; + + RandomAccessFileEntity *GetRAFEntity() const + { + return rafEntity.get(); + } + + FsRandomAccessFile(const FsRandomAccessFile &other) = delete; + FsRandomAccessFile &operator=(const FsRandomAccessFile &other) = delete; + + FsRandomAccessFile(FsRandomAccessFile &&other) noexcept : rafEntity(move(other.rafEntity)) + { + other.rafEntity = nullptr; + } + + FsRandomAccessFile &operator=(FsRandomAccessFile &&other) noexcept + { + if (this != &other) { + rafEntity = move(other.rafEntity); + other.rafEntity = nullptr; + } + return *this; + } + + ~FsRandomAccessFile() = default; + + FsResult SetFilePointerSync(const int64_t &fp) const; + FsResult WriteSync(const string &buffer, const optional &options = nullopt) const; + FsResult WriteSync(const ArrayBuffer &buffer, const optional &options = nullopt) const; + FsResult ReadSync(ArrayBuffer &buffer, const optional &options = nullopt) const; + FsResult CloseSync() const; + + FsResult GetFD() const; + FsResult GetFPointer() const; + + static FsResult Constructor(); + +private: + unique_ptr rafEntity; + explicit FsRandomAccessFile(unique_ptr entity) : rafEntity(move(entity)) {} +}; +const string readProcedureName = "FileIORandomAccessFileRead"; +const string writeProcedureName = "FileIORandomAccessFileWrite"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif //INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_FS_RANDOMACCESSFILE_H \ No newline at end of file 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 index 3f5b12a7f268a3781cbc5031adb9c3c11591d066..6d80bebec09effa4bda3e0ab6f2178df139e9b89 100644 --- a/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_entity.h +++ b/interfaces/kits/js/src/mod_fs/class_randomaccessfile/randomaccessfile_entity.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * Copyright (c) 2025 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 @@ -16,17 +16,21 @@ #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 #include #include "fd_guard.h" -#include "n_val.h" +#include "filemgmt_libhilog.h" namespace OHOS { namespace FileManagement { namespace ModuleFileIO { +using namespace std; + const int64_t INVALID_POS = -1; struct RandomAccessFileEntity { - std::unique_ptr fd = {nullptr}; + unique_ptr fd = {nullptr}; int64_t filePointer = 0; int64_t start = INVALID_POS; int64_t end = INVALID_POS; @@ -34,4 +38,4 @@ struct RandomAccessFileEntity { } // namespace ModuleFileIO } // namespace FileManagement } // namespace OHOS -#endif \ No newline at end of file +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_RANDOMACCESSFILE_RANDOMACCESSFILE_ENTITY_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5f8b55b93c91b0b2b2c1b9a046cdc2968dab24f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025 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 "reader_iterator_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "reader_iterator_result_ani.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +ani_object ReaderIteratorAni::Wrap(ani_env *env, const FsReaderIterator *it) +{ + static const char *className = "L@ohos/file/fs/ReaderIteratorInner;"; + + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "J:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(it)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", className); + return nullptr; + } + + return obj; +} + +FsReaderIterator *ReaderIteratorAni::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsReaderIterator err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsReaderIterator *readeriterator = reinterpret_cast(ptrValue); + return readeriterator; +} + +ani_object ReaderIteratorAni::Next(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsReaderIterator = Unwrap(env, object); + if (fsReaderIterator == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsReaderIterator->Next(); + if (!ret.IsSuccess()) { + HILOGE("Cannot get readeriterator next!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return {}; + } + auto nextRet = ret.GetData().value(); + auto result = ReaderIteratorResultAni::Wrap(env, &nextRet); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.h b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..31d70abc24f16b2ddc84c4bd627c20580e0ce001 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_ani.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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_READER_ITERATOR_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_READER_ITERATOR_ANI_H + +#include + +#include "fs_reader_iterator.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReaderIteratorAni final { +public: + static ani_object Wrap(ani_env *env, const FsReaderIterator *it); + static FsReaderIterator *Unwrap(ani_env *env, ani_object object); + static ani_object Next(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_READER_ITERATOR_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0ea8f121b13ffdf8bf88536279e737b91519685b --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 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 "reader_iterator_result_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +ani_object ReaderIteratorResultAni::Wrap(ani_env *env, const ReaderIteratorResult *result) +{ + static const char *className = "L@ohos/file/fs/ReaderIteratorResultInner;"; + + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "J:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(result)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", className); + return nullptr; + } + + const auto &done = result->done; + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "done", static_cast(done))) { + HILOGE("Set 'done' field value failed!"); + return nullptr; + } + + const auto &value = result->value; + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "value", value)) { + HILOGE("Set 'value' field value failed!"); + return nullptr; + } + + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.h b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..0f683784654fe6da7db2415df97312043de59b9c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/ani/reader_iterator_result_ani.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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_READER_ITERATOR_RESULT_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_READER_ITERATOR_RESULT_ANI_H + +#include + +#include "fs_reader_iterator.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReaderIteratorResultAni final { +public: + static ani_object Wrap(ani_env *env, const ReaderIteratorResult *result); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_READER_ITERATOR_RESULT_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.cpp b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..80321d51f126f318d7ae4fd8c78ba76db64ff928 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 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 "fs_reader_iterator.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "rust_file.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +FsResult FsReaderIterator::Constructor() +{ + auto entity = CreateUniquePtr(); + if (entity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + FsReaderIterator *it = new FsReaderIterator(move(entity)); + + if (it == nullptr) { + HILOGE("Failed to create FsReaderIterator object on heap."); + return FsResult::Error(ENOMEM); + } + return FsResult::Success(move(it)); +} + +FsResult FsReaderIterator::Next() +{ + if (entity == nullptr) { + HILOGE("Failed to get reader iterator entity"); + return FsResult::Error(UNKNOWN_ERR); + } + + Str *str = NextLine(entity->iterator); + if (str == nullptr && entity->offset != 0) { + HILOGE("Failed to get next line, error:%{public}d", errno); + return FsResult::Error(errno); + } + + ReaderIteratorResult result; + bool done = entity->offset == 0; + result.done = done; + if (str != nullptr) { + std::string value(str->str, str->len); + result.value = value; + entity->offset -= static_cast(str->len); + } else { + result.value = ""; + } + StrFree(str); + + return FsResult::Success(move(result)); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.h b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..bc534da09eb0acbaa8261bfe599580c6fdbda9aa --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_readeriterator/fs_reader_iterator.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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_READERITERATOR_FS_READERITERATOR_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_FS_READERITERATOR_H + +#include "filemgmt_libfs.h" +#include "readeriterator_entity.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +struct ReaderIteratorResult { + bool done; + std::string value; +}; + +class FsReaderIterator final { +public: + static FsResult Constructor(); + + ReaderIteratorEntity *GetReaderIteratorEntity() const + { + return entity.get(); + } + + FsResult Next(); + +private: + unique_ptr entity; + explicit FsReaderIterator(unique_ptr entity) : entity(move(entity)) {}; +}; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_READERITERATOR_FS_READERITERATOR_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/ani/lstat_ani.cpp b/interfaces/kits/js/src/mod_fs/class_stat/ani/lstat_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f4379ac5fe8dd63c2d8b1449d3f9563e3a09599d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/ani/lstat_ani.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2025 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 "lstat_ani.h" + +#include +#include + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "lstat_core.h" +#include "stat_wrapper.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object LstatAni::LstatSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path) +{ + auto [succPath, filePath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("The first argument requires filepath"); + ErrorHandler::Throw(env, EINVAL); + return {}; + } + + auto ret = LstatCore::DoLstat(filePath); + if (!ret.IsSuccess()) { + HILOGE("DoStat failed!"); + const FsError &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return {}; + } + + auto fsStat = ret.GetData().value(); + auto [status, statObject] = StatWrapper::Wrap(env, fsStat); + if (status != ANI_OK) { + delete fsStat; + fsStat = nullptr; + HILOGE("Wrap stat object failed!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return {}; + } + + return statObject; +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/ani/lstat_ani.h b/interfaces/kits/js/src/mod_fs/class_stat/ani/lstat_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..140d92807596db8a643bf1a298c9caebb7b3f27f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/ani/lstat_ani.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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_ANI_LSTAT_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_LSTAT_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class LstatAni final { +public: + static ani_object LstatSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_LSTAT_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_ani.cpp b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95b92f9583c75bd005a8636f27f7358cef352404 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_ani.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025 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 "stat_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "stat_core.h" +#include "stat_wrapper.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object StatAni::StatSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_object file) +{ + auto [succPath, fileInfo] = TypeConverter::ToFileInfo(env, file); + if (!succPath) { + HILOGE("The first argument requires filepath/fd"); + ErrorHandler::Throw(env, EINVAL); + return {}; + } + + auto ret = StatCore::DoStat(fileInfo); + if (!ret.IsSuccess()) { + HILOGE("DoStat failed!"); + const FsError &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return {}; + } + + auto fsStat = ret.GetData().value(); + auto [status, statObject] = StatWrapper::Wrap(env, fsStat); + if (status != ANI_OK) { + delete fsStat; + fsStat = nullptr; + HILOGE("Wrap stat object failed!"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return {}; + } + + return statObject; +} + +ani_boolean StatAni::IsBlockDevice(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsBlockDevice(); + return ani_boolean(ret); +} + +ani_boolean StatAni::IsCharacterDevice(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsCharacterDevice(); + return ani_boolean(ret); +} + +ani_boolean StatAni::IsDirectory(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsDirectory(); + return ani_boolean(ret); +} + +ani_boolean StatAni::IsFIFO(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsFIFO(); + return ani_boolean(ret); +} + +ani_boolean StatAni::IsFile(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsFile(); + return ani_boolean(ret); +} + +ani_boolean StatAni::IsSocket(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsSocket(); + return ani_boolean(ret); +} + +ani_boolean StatAni::IsSymbolicLink(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStat = StatWrapper::Unwrap(env, object); + if (fsStat == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return ANI_FALSE; + } + + auto ret = fsStat->IsSymbolicLink(); + return ani_boolean(ret); +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_ani.h b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..8fd891c720efb728048de1bb87344569f42f747f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_ani.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 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_ANI_STAT_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_STAT_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class StatAni final { +public: + static ani_object StatSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_object file); + static ani_boolean IsBlockDevice(ani_env *env, [[maybe_unused]] ani_object object); + static ani_boolean IsCharacterDevice(ani_env *env, [[maybe_unused]] ani_object object); + static ani_boolean IsDirectory(ani_env *env, [[maybe_unused]] ani_object object); + static ani_boolean IsFIFO(ani_env *env, [[maybe_unused]] ani_object object); + static ani_boolean IsFile(ani_env *env, [[maybe_unused]] ani_object object); + static ani_boolean IsSocket(ani_env *env, [[maybe_unused]] ani_object object); + static ani_boolean IsSymbolicLink(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_STAT_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..02a9bca9fc8b1a7d4bac48c492a1e73069ccb491 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_wrapper.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2025 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 "stat_wrapper.h" + +#include +#include + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +static ani_status SetNumProperty( + ani_env *env, const ani_class &cls, ani_object &object, const char *name, ani_double &value) +{ + ani_method setter; + ani_status ret; + if ((ret = env->Class_FindMethod(cls, name, nullptr, &setter)) != ANI_OK) { + HILOGE("Class_FindMethod Fail %{private}s, err: %{private}d", name, ret); + return ret; + } + + return env->Object_CallMethod_Void(object, setter, value); +} + +static ani_status SetBigIntProperty( + ani_env *env, const ani_class &statCls, ani_object &statObject, const char *name, ani_double &value) +{ + ani_object object = {}; + static const char *className = "Lescompat/BigInt;"; + ani_class cls; + ani_status ret; + + if ((ret = env->FindClass(className, &cls)) != ANI_OK) { + HILOGE("Not found %{private}s, err: %{private}d", className, ret); + return ret; + } + + ani_method ctor; + if ((ret = env->Class_FindMethod(cls, "", "D:V", &ctor)) != ANI_OK) { + HILOGE("Not found ctor, err: %{private}d", ret); + return ret; + } + + if ((ret = env->Object_New(cls, ctor, &object, value)) != ANI_OK) { + HILOGE("New BigIntProperty Fail, err: %{private}d", ret); + return ret; + } + + ani_method setter; + if ((ret = env->Class_FindMethod(statCls, name, nullptr, &setter)) != ANI_OK) { + HILOGE("Class_FindMethod Fail %{private}s, err: %{private}d", name, ret); + return ret; + } + + return env->Object_CallMethod_Void(statObject, setter, object); +} + +static ani_int GetLocationEnumIndex(const Location &value) +{ + switch (value) { + case LOCAL: + return ani_int(0); + case CLOUD: + return ani_int(1); + } +} + +static ani_status SetEnumLocation( + ani_env *env, const ani_class &cls, ani_object &object, const char *name, const Location &value) +{ + ani_method setter; + ani_status ret; + if ((ret = env->Class_FindMethod(cls, name, nullptr, &setter)) != ANI_OK) { + HILOGE("Class_FindMethod Fail %{private}s, err: %{private}d", name, ret); + return ret; + } + + return env->Object_CallMethod_Void(object, setter, GetLocationEnumIndex(value)); +} + +static ani_status SetProperties(ani_env *env, const ani_class &cls, ani_object &statObject, FsStat *fsStat) +{ + ani_status ret; + + vector> numProperties = { + { "mode", ani_double(static_cast(fsStat->GetMode())) }, + { "uid", ani_double(static_cast(fsStat->GetUid())) }, + { "gid", ani_double(static_cast(fsStat->GetGid())) }, + { "size", ani_double(static_cast(fsStat->GetSize())) }, + { "atime", ani_double(static_cast(fsStat->GetAtime())) }, + { "mtime", ani_double(static_cast(fsStat->GetMtime())) }, + { "ctime", ani_double(static_cast(fsStat->GetCtime())) }, + }; + for (auto iter : numProperties) { + ret = SetNumProperty(env, cls, statObject, iter.first, iter.second); + if (ret != ANI_OK) { + HILOGE("Object_CallMethod_Void Fail %{private}s, err: %{private}d", iter.first, ret); + return ret; + } + } + + vector> bigIntProperties = { + { "ino", ani_double(static_cast(fsStat->GetIno())) }, + { "atimeNs", ani_double(static_cast(fsStat->GetAtimeNs())) }, + { "mtimeNs", ani_double(static_cast(fsStat->GetMtimeNs())) }, + { "ctimeNs", ani_double(static_cast(fsStat->GetCtimeNs())) }, + }; + for (auto iter : bigIntProperties) { + ret = SetBigIntProperty(env, cls, statObject, iter.first, iter.second); + if (ret != ANI_OK) { + HILOGE("Object_CallMethod_Void Fail %{private}s, err: %{private}d", iter.first, ret); + return ret; + } + } + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + if ((ret = SetEnumLocation(env, cls, statObject, "location", static_cast(fsStat->GetLocation()))) != + ANI_OK) { + HILOGE("Object_CallMethod_Void Fail location, err: %{private}d", ret); + return ret; + } +#endif + + return ANI_OK; +} + +tuple StatWrapper::Wrap(ani_env *env, FsStat *fsStat) +{ + ani_object statObject = {}; + static const char *className = "L@ohos/file/fs/StatInner;"; + ani_class cls; + ani_status ret; + + if ((ret = env->FindClass(className, &cls)) != ANI_OK) { + HILOGE("Not found %{private}s, err: %{private}d", className, ret); + return { ret, statObject }; + } + + ani_method ctor; + if ((ret = env->Class_FindMethod(cls, "", "J:V", &ctor)) != ANI_OK) { + HILOGE("Not found ctor, err: %{private}d", ret); + return { ret, statObject }; + } + + if ((ret = env->Object_New(cls, ctor, &statObject, reinterpret_cast(fsStat))) != ANI_OK) { + HILOGE("New StatInner Fail, err: %{private}d", ret); + return { ret, statObject }; + } + + if ((ret = SetProperties(env, cls, statObject, fsStat)) != ANI_OK) { + HILOGE("SetProperties Fail, err: %{private}d", ret); + return { ret, statObject }; + } + + return { ANI_OK, statObject }; +} + +FsStat* StatWrapper::Unwrap(ani_env *env, ani_object object) +{ + ani_long fsStat; + auto ret = env->Object_GetFieldByName_Long(object, "nativeStat", &fsStat); + if (ret != ANI_OK) { + HILOGE("Unwrap fsStat err: %{private}d", ret); + return nullptr; + } + return reinterpret_cast(fsStat); +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_wrapper.h b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..77bbcbe6ff1b46fe0a35f564914b5a82c8395271 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/ani/stat_wrapper.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 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_ANI_STAT_WRAPPER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_STAT_WRAPPER_H + +#include + +#include "fs_stat.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; + +class StatWrapper final { +public: + static tuple Wrap(ani_env *env, FsStat *fsStat); + static FsStat* Unwrap(ani_env *env, ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_STAT_WRAPPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/fs_stat.cpp b/interfaces/kits/js/src/mod_fs/class_stat/fs_stat.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49b1b53d80e85ecd6413f27badc52f7e37031510 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/fs_stat.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2025 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 "fs_stat.h" + +#include +#include +#include +#include +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +#include +#endif + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +bool FsStat::CheckStatMode(mode_t mode) +{ + return (entity->stat_.st_mode & S_IFMT) == mode; +} + +bool FsStat::IsBlockDevice() +{ + return CheckStatMode(S_IFBLK); +} + +bool FsStat::IsCharacterDevice() +{ + return CheckStatMode(S_IFCHR); +} + +bool FsStat::IsDirectory() +{ + return CheckStatMode(S_IFDIR); +} + +bool FsStat::IsFIFO() +{ + return CheckStatMode(S_IFIFO); +} + +bool FsStat::IsFile() +{ + return CheckStatMode(S_IFREG); +} + +bool FsStat::IsSocket() +{ + return CheckStatMode(S_IFSOCK); +} + +bool FsStat::IsSymbolicLink() +{ + return CheckStatMode(S_IFLNK); +} + +int64_t FsStat::GetIno() +{ + return entity->stat_.st_ino; +} + +int64_t FsStat::GetMode() +{ + return entity->stat_.st_mode & S_PERMISSION; +} + +int64_t FsStat::GetUid() +{ + return entity->stat_.st_uid; +} + +int64_t FsStat::GetGid() +{ + return entity->stat_.st_gid; +} + +int64_t FsStat::GetSize() +{ + return entity->stat_.st_size; +} + +int64_t FsStat::GetAtime() +{ + return static_cast(entity->stat_.st_atim.tv_sec); +} + +int64_t FsStat::GetMtime() +{ + return static_cast(entity->stat_.st_mtim.tv_sec); +} + +int64_t FsStat::GetCtime() +{ + return static_cast(entity->stat_.st_ctim.tv_sec); +} + +int64_t FsStat::GetAtimeNs() +{ + return static_cast(entity->stat_.st_atim.tv_sec * SECOND_TO_NANOSECOND + entity->stat_.st_atim.tv_nsec); +} + +int64_t FsStat::GetMtimeNs() +{ + return static_cast(entity->stat_.st_mtim.tv_sec * SECOND_TO_NANOSECOND + entity->stat_.st_mtim.tv_nsec); +} + +int64_t FsStat::GetCtimeNs() +{ + return static_cast(entity->stat_.st_ctim.tv_sec * SECOND_TO_NANOSECOND + entity->stat_.st_ctim.tv_nsec); +} + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +int32_t FsStat::GetLocation() +{ + std::unique_ptr value = CreateUniquePtr(MAX_ATTR_NAME); + if (value == nullptr) { + HILOGE("Getxattr memory out, errno is %{public}d", errno); + return ENOMEM; + } + + ssize_t size = 0; + if (entity->fileInfo_->isPath) { + size = getxattr(entity->fileInfo_->path.get(), CLOUD_LOCATION_ATTR.c_str(), value.get(), MAX_ATTR_NAME); + } else { + size = fgetxattr(entity->fileInfo_->fdg->GetFD(), CLOUD_LOCATION_ATTR.c_str(), value.get(), MAX_ATTR_NAME); + } + Location defaultLocation = LOCAL; + if (size <= 0) { + if (errno != ENODATA && errno != EOPNOTSUPP) { + HILOGE("Getxattr value failed, errno is %{public}d", errno); + } + return static_cast(defaultLocation); + } + std::string location = string(value.get(), static_cast(size)); + if (!std::all_of(location.begin(), location.end(), ::isdigit)) { + HILOGE("Getxattr location is not all digit!"); + return static_cast(defaultLocation); + } + defaultLocation = static_cast(atoi(location.c_str())); + return static_cast(defaultLocation); +} +#endif + +FsStat *FsStat::Constructor() +{ + auto entity = CreateUniquePtr(); + if (entity == nullptr) { + HILOGE("Failed to request heap memory."); + return nullptr; + } + + return new FsStat(move(entity)); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/fs_stat.h b/interfaces/kits/js/src/mod_fs/class_stat/fs_stat.h new file mode 100644 index 0000000000000000000000000000000000000000..802015087cf5ad5f48c21e73b7179474c99390fa --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/fs_stat.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 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_STAT_FS_STAT_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STAT_FS_STAT_H + +#include "filemgmt_libfs.h" +#include "fs_stat_entity.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +const int64_t SECOND_TO_NANOSECOND = 1e9; +constexpr int S_PERMISSION = 00000777; +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +const size_t MAX_ATTR_NAME = 64; +const std::string CLOUD_LOCATION_ATTR = "user.cloud.location"; +#endif +class FsStat final { +public: + static FsStat *Constructor(); + + StatEntity *GetStatEntity() const + { + return entity.get(); + } + + bool IsBlockDevice(); + bool IsCharacterDevice(); + bool IsDirectory(); + bool IsFIFO(); + bool IsFile(); + bool IsSocket(); + bool IsSymbolicLink(); + + int64_t GetIno(); + int64_t GetMode(); + int64_t GetUid(); + int64_t GetGid(); + int64_t GetSize(); + int64_t GetAtime(); + int64_t GetMtime(); + int64_t GetCtime(); + int64_t GetAtimeNs(); + int64_t GetMtimeNs(); + int64_t GetCtimeNs(); +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + int32_t GetLocation(); +#endif + +private: + unique_ptr entity; + bool CheckStatMode(mode_t mode); + explicit FsStat(unique_ptr entity) : entity(move(entity)) {}; +}; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STAT_FS_STAT_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/fs_stat_entity.h b/interfaces/kits/js/src/mod_fs/class_stat/fs_stat_entity.h new file mode 100644 index 0000000000000000000000000000000000000000..772bad4ed5698afabd54f77b776bb59fcb3da7ef --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/fs_stat_entity.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_STAT_FS_STAT_ENTITY_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STAT_FS_STAT_ENTITY_H + +#include +#include "fs_utils.h" +#include "uv.h" + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +enum Location { LOCAL = 1 << 0, CLOUD = 1 << 1 }; +#endif +namespace OHOS::FileManagement::ModuleFileIO { +struct StatEntity { + uv_stat_t stat_; +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + std::shared_ptr fileInfo_; +#endif +}; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STAT_FS_STAT_ENTITY_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/stat_instantiator.cpp b/interfaces/kits/js/src/mod_fs/class_stat/stat_instantiator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..81e6a502e9bffd164ab8d05af725e2aa45618cf6 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/stat_instantiator.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2025 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 "stat_instantiator.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +FsStat* StatInstantiator::InstantiateStat(const uv_stat_t &buf, shared_ptr fileInfo) +{ + auto stat = FsStat::Constructor(); + if (stat == nullptr) { + return nullptr; + } + + auto entity = stat->GetStatEntity(); + entity->stat_ = buf; + entity->fileInfo_ = fileInfo; + + return stat; +} +#endif + +FsStat* StatInstantiator::InstantiateStat(const uv_stat_t &buf) +{ + auto stat = FsStat::Constructor(); + if (stat == nullptr) { + return nullptr; + } + + auto entity = stat->GetStatEntity(); + entity->stat_ = buf; + + return stat; +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stat/stat_instantiator.h b/interfaces/kits/js/src/mod_fs/class_stat/stat_instantiator.h new file mode 100644 index 0000000000000000000000000000000000000000..384186885e3400c122a404b2220edf8d5d28d731 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stat/stat_instantiator.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2025 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_STAT_INSTANTIATOR_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STAT_INSTANTIATOR_H + +#include "fs_stat.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +class StatInstantiator final { +public: +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + static FsStat* InstantiateStat(const uv_stat_t &buf, shared_ptr fileInfo); +#endif + static FsStat* InstantiateStat(const uv_stat_t &buf); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STAT_INSTANTIATOR_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abce84a4d07513b72e48dd90e3495560b081af26 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.cpp @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2025 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_ani.h" + +#include +#include + +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fs_stream.h" +#include "fs_utils.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +static tuple> ToReadOptions(ani_env *env, ani_object obj) +{ + ReadOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + return { true, make_optional(move(options)) }; +} + +static tuple> ToWriteOptions(ani_env *env, ani_object obj) +{ + WriteOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding; + return { true, make_optional(move(options)) }; +} + +static std::tuple ParseStringBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + env->FindClass("Lstd/core/String;", &cls); + + ani_boolean isString; + env->Object_InstanceOf(buf, cls, &isString); + if (!isString) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, std::move(result) }; +} + +static std::tuple ParseArrayBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + env->FindClass("Lescompat/ArrayBuffer;", &cls); + + ani_boolean isArrayBuffer; + env->Object_InstanceOf(buf, cls, &isArrayBuffer); + if (!isArrayBuffer) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, std::move(result) }; +} + +static FsStream *Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsStream *stream = reinterpret_cast(ptrValue); + return stream; +} + +void StreamAni::Close(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = fsStream->Close(); + if (!ret.IsSuccess()) { + HILOGE("Cannot close fsStream!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void StreamAni::Flush(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = fsStream->Flush(); + if (!ret.IsSuccess()) { + HILOGE("Cannot flush fsStream!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +ani_double StreamAni::Write(ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + return -1; + } + + auto [succOp, op] = ToWriteOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + return -1; + } + + auto [isString, stringBuffer] = ParseStringBuffer(env, buf); + if (isString) { + auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer); + if (!succBuf) { + HILOGE("Failed to resolve stringBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = fsStream->Write(buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + return ret.GetData().value(); + } + + auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf); + if (isArrayBuffer) { + auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = fsStream->Write(buffer, op); + if (!ret.IsSuccess()) { + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + HILOGE("write buffer failed!"); + return -1; + } + return static_cast(ret.GetData().value()); + } + + HILOGE("Unsupported buffer type!"); + ErrorHandler::Throw(env, EINVAL); + return -1; +} + +ani_double StreamAni::Read(ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buffer, ani_object options) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succOp, op] = ToReadOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = fsStream->Read(arrayBuffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} + +ani_double StreamAni::Seek(ani_env *env, [[maybe_unused]] ani_object object, ani_double offset, ani_object whence) +{ + auto fsStream = Unwrap(env, object); + if (fsStream == nullptr) { + HILOGE("Cannot unwrap fsStream!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succ, typeOpt] = TypeConverter::ToOptionalInt32(env, whence); + if (!succ) { + HILOGE("Invalied whence type"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = fsStream->Seek(static_cast(offset), typeOpt); + if (!ret.IsSuccess()) { + HILOGE("seek failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..91fdb9852a432c0dbc754b8763ab53d6c5046802 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_ani.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 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_STREAM_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class StreamAni final { +public: + static void Close(ani_env *env, [[maybe_unused]] ani_object object); + static void Flush(ani_env *env, [[maybe_unused]] ani_object object); + static ani_double Write(ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options); + static ani_double Read( + ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buffer, ani_object options); + static ani_double Seek(ani_env *env, [[maybe_unused]] ani_object object, ani_double offset, ani_object whence); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31ff9ec263797ba2f333c5a252a4b5a4daba373e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2025 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_wrapper.h" + +#include + +#include "ani_helper.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace std; + +FsStream *StreamWrapper::Unwrap(ani_env *env, ani_object object) +{ + ani_long nativePtr; + auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr); + if (ret != ANI_OK) { + HILOGE("Unwrap fsFile err: %{private}d", ret); + return nullptr; + } + uintptr_t ptrValue = static_cast(nativePtr); + FsStream *stream = reinterpret_cast(ptrValue); + return stream; +} + +ani_object StreamWrapper::Wrap(ani_env *env, const FsStream *stream) +{ + static const char *className = "L@ohos/file/fs/StreamInner;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "J:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(stream)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", className); + return nullptr; + } + + return obj; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..a99f6d4ad2c85500c8193730d661693d83a2044c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/ani/stream_wrapper.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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_STREAM_WRAPPER_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_WRAPPER_H + +#include +#include "fs_stream.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class StreamWrapper final { +public: + static FsStream *Unwrap(ani_env *env, ani_object object); + static ani_object Wrap(ani_env *env, const FsStream *stream); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_STREAM_WRAPPER_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a39e3506b6513e805093e64852349d00fe4fe98 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2025 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 "fs_stream.h" + +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +std::shared_ptr FsStream::GetFilePtr() +{ + std::lock_guard lock(mtx); + if (!streamEntity->fp) { + return nullptr; + } + return streamEntity->fp; +} + +static tuple ValidWriteArg(const size_t bufLen, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + + if (bufLen > UINT_MAX) { + HILOGE("The Size of buffer is too large"); + return { false, 0, offset }; + } + + optional lengthOp = nullopt; + optional offsetOp = nullopt; + optional encodingOp = nullopt; + if (options.has_value()) { + WriteOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + encodingOp = op.encoding; + } + + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, 0, offset }; + } + + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, 0, offset }; + } + } + + if (encodingOp.has_value()) { + if (encodingOp.value() != "utf-8") { + HILOGE("option.encoding shall be utf-8"); + return { false, 0, offset }; + } + } + return { true, retLen, offset }; +} + +static tuple ValidReadArg(const size_t bufLen, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + + if (bufLen > UINT_MAX) { + HILOGE("The Size of buffer is too large"); + return { false, 0, offset }; + } + + optional lengthOp = nullopt; + optional offsetOp = nullopt; + if (options.has_value()) { + ReadOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + } + + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, 0, offset }; + } + + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, 0, offset }; + } + } + return { true, retLen, offset }; +} + +FsResult FsStream::Write(const ArrayBuffer &buf, const optional &options) +{ + auto fp = GetFilePtr(); + if (!fp) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(EIO); + } + + auto [succ, retLen, offset] = ValidWriteArg(buf.length, options); + if (!succ) { + HILOGE("Invalid options"); + return FsResult::Error(EINVAL); + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), SEEK_SET); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + size_t writeLen = fwrite(buf.buf, 1, retLen, fp.get()); + if ((writeLen == 0) && (writeLen != retLen)) { + HILOGE("Failed to fwrite stream"); + return FsResult::Error(EIO); + } + return FsResult::Success(writeLen); +} + +FsResult FsStream::Write(const string &buf, const optional &options) +{ + auto fp = GetFilePtr(); + if (!fp) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(EIO); + } + + size_t bufLen = static_cast(buf.length()); + + auto [succ, retLen, offset] = ValidWriteArg(bufLen, options); + if (!succ) { + HILOGE("Invalid options"); + return FsResult::Error(EINVAL); + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), SEEK_SET); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + size_t writeLen = fwrite(buf.c_str(), 1, retLen, fp.get()); + if ((writeLen == 0) && (writeLen != retLen)) { + HILOGE("Failed to fwrite stream"); + return FsResult::Error(EIO); + } + return FsResult::Success(writeLen); +} + +FsResult FsStream::Read(ArrayBuffer &buf, const optional &options) +{ + auto fp = GetFilePtr(); + if (!fp) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(EIO); + } + + auto [succ, retLen, offset] = ValidReadArg(buf.length, options); + if (!succ) { + HILOGE("Invalid options"); + return FsResult::Error(EINVAL); + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), SEEK_SET); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + size_t actLen = fread(buf.buf, 1, retLen, fp.get()); + if ((actLen != static_cast(retLen) && !feof(fp.get())) || ferror(fp.get())) { + HILOGE("Invalid buffer size or pointer, actlen: %{public}zu", actLen); + return FsResult::Error(EIO); + } + + return FsResult::Success(actLen); +} + +FsResult FsStream::Flush() +{ + auto fp = GetFilePtr(); + if (fp == nullptr) { + HILOGE("Failed to get entity of Stream"); + return FsResult::Error(EIO); + } + + int ret = fflush(fp.get()); + if (ret < 0) { + HILOGE("Failed to fflush file in the stream, ret: %{public}d", ret); + return FsResult::Error(errno); + } + + return FsResult::Success(); +} + +FsResult FsStream::Close() +{ + if (!streamEntity) { + HILOGE("Failed to get entity of Stream, may closed twice"); + return FsResult::Error(EIO); + } + streamEntity = nullptr; + return FsResult::Success(); +} + +FsResult FsStream::Seek(const int64_t &offset, const optional &typeOpt) +{ + int whence = SEEK_SET; + + auto fp = GetFilePtr(); + if (fp == nullptr) { + HILOGE("Failed to get file ptr"); + return FsResult::Error(ENOENT); + } + + if (typeOpt.has_value()) { + int pos = typeOpt.value(); + if (pos < SEEK_SET || pos > SEEK_END) { + HILOGE("Invalid whence"); + return FsResult::Error(EINVAL); + } + whence = pos; + } + + if (offset >= 0) { + int ret = fseek(fp.get(), static_cast(offset), whence); + if (ret < 0) { + HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret); + return FsResult::Error(errno); + } + } + + int64_t res = ftell(fp.get()); + if (res < 0) { + HILOGE("Failed to tell, error:%{public}d", errno); + return FsResult::Error(errno); + } + + return FsResult::Success(res); +} + +FsResult FsStream::Constructor() +{ + auto rafEntity = CreateUniquePtr(); + if (rafEntity == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + FsStream *fsStreamPtr = new FsStream(move(rafEntity)); + + if (fsStreamPtr == nullptr) { + HILOGE("Failed to create FsStream object on heap."); + return FsResult::Error(ENOMEM); + } + + return FsResult::Success(move(fsStreamPtr)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..1ee619776dae44292694282b6c1673d8442f7b20 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/fs_stream.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 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_FS_STREAM_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_FS_STREAM_H + +#include "stream_entity.h" + +#include +#include +#include + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct WriteOptions { + optional length = nullopt; + optional offset = nullopt; + optional encoding = nullopt; +}; + +struct ReadOptions { + optional length = nullopt; + optional offset = nullopt; +}; + +class FsStream final { +public: + StreamEntity *GetStreamEntity() const + { + return streamEntity.get(); + } + + FsStream(const FsStream &) = delete; + FsStream &operator=(const FsStream &) = delete; + + std::shared_ptr GetFilePtr(); + FsResult Write(const ArrayBuffer &buf, const optional &options = nullopt); + FsResult Write(const string &buf, const optional &options = nullopt); + FsResult Read(ArrayBuffer &buf, const optional &options = nullopt); + FsResult Close(); + FsResult Flush(); + FsResult Seek(const int64_t &offset, const optional &typeOpt = nullopt); + + ~FsStream() = default; + static FsResult Constructor(); + +private: + std::mutex mtx; + unique_ptr streamEntity; + explicit FsStream(unique_ptr entity) : streamEntity(move(entity)) {} +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_FS_STREAM_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e28dfa77ce4a984cdf93ce3a48b12c84e9882978 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2025 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_instantiator.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "stream_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult StreamInstantiator::InstantiateStream(FILE *file) +{ + FsResult result = FsStream::Constructor(); + if (!result.IsSuccess()) { + HILOGE("Failed to instantiate class"); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + return FsResult::Error(EIO); + } + + const FsStream *objStream = result.GetData().value(); + if (!objStream) { + HILOGE("Failed to get FsStream"); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + return FsResult::Error(EIO); + } + + auto *streamEntity = objStream->GetStreamEntity(); + if (!streamEntity) { + HILOGE("Failed to get streamEntity"); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + delete objStream; + objStream = nullptr; + return FsResult::Error(EIO); + } + + auto fp = std::shared_ptr(file, fclose); + if (fp == nullptr) { + HILOGE("Failed to request heap memory."); + int ret = fclose(file); + if (ret < 0) { + HILOGE("Failed to close file"); + } + delete objStream; + objStream = nullptr; + return FsResult::Error(ENOMEM); + } + + streamEntity->fp.swap(fp); + return result; +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h new file mode 100644 index 0000000000000000000000000000000000000000..bf98d7b5305804dc460e210491fcd66ab79ffe96 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_stream/stream_instantiator.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_INSTANTIATOR_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_INSTANTIATOR_H + +#include "filemgmt_libfs.h" +#include "fs_stream.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +class StreamInstantiator { +public: + static FsResult InstantiateStream(FILE *file); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_STREAM_INSTANTIATOR_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_tasksignal/ani/task_signal_ani.cpp b/interfaces/kits/js/src/mod_fs/class_tasksignal/ani/task_signal_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f22a814f94d56868bfe4f8051093be06a053930e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_tasksignal/ani/task_signal_ani.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 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 "task_signal_ani.h" + +#include "ani_helper.h" +#include "copy_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "task_signal_entity_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +static TaskSignalEntityCore *Unwrap(ani_env *env, ani_object object) +{ + ani_long entity; + auto ret = env->Object_GetFieldByName_Long(object, "nativeTaskSignal", &entity); + if (ret != ANI_OK) { + HILOGE("Unwrap taskSignalEntityCore err: %{private}d", ret); + return nullptr; + } + return reinterpret_cast(entity); +} + +void TaskSignalAni::Cancel(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto entity = Unwrap(env, object); + if (entity == nullptr) { + ErrorHandler::Throw(env, EINVAL); + return; + } + if (entity->taskSignal_ == nullptr) { + HILOGE("Failed to get watcherEntity when stop."); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = entity->taskSignal_->Cancel(); + if (ret != NO_ERROR) { + HILOGE("Failed to cancel the task."); + ErrorHandler::Throw(env, CANCEL_ERR); + return; + } +} + +void TaskSignalAni::OnCancel(ani_env *env, [[maybe_unused]] ani_object object) +{ + auto entity = Unwrap(env, object); + if (entity == nullptr) { + ErrorHandler::Throw(env, EINVAL); + return; + } + if (entity->taskSignal_ == nullptr) { + HILOGE("Failed to get watcherEntity when stop."); + ErrorHandler::Throw(env, EINVAL); + return; + } + + ani_ref globalObj; + auto status = env->GlobalReference_Create(object, &globalObj); + if (status != ANI_OK) { + HILOGE("GlobalReference_Create, err: %{private}d", status); + return; + } + ani_vm *vm = nullptr; + env->GetVM(&vm); + auto cb = [vm, &globalObj](string filePath) -> void { + auto env = AniHelper::GetThreadEnv(vm); + if (env == nullptr) { + HILOGE("failed to GetThreadEnv"); + return; + } + + // std::vector vec; + auto [succPath, path] = TypeConverter::ToAniString(env, filePath); + if (!succPath) { + HILOGE("ToAniString failed"); + return; + } + + auto ret = env->Object_CallMethodByName_Void(static_cast(globalObj), + "onCancelCallback", nullptr, path); + if (ret != ANI_OK) { + HILOGE("Call onCancelCallback failed, err: %{private}d", ret); + return; + } + }; + auto callbackContext = std::make_shared(cb); + entity->callbackContextCore_ = callbackContext; + entity->taskSignal_->SetTaskSignalListener(entity); +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_tasksignal/ani/task_signal_ani.h b/interfaces/kits/js/src/mod_fs/class_tasksignal/ani/task_signal_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..6db3301ce5973d5a3605120510c340ee6dff2e2f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_tasksignal/ani/task_signal_ani.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_FILE_API_TASK_SIGNAL_ANI_H +#define FILEMANAGEMENT_FILE_API_TASK_SIGNAL_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class TaskSignalAni final { +public: + static void Cancel(ani_env *env, [[maybe_unused]] ani_object object); + static void OnCancel(ani_env *env, [[maybe_unused]] ani_object object); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // FILEMANAGEMENT_FILE_API_TASK_SIGNAL_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_tasksignal/task_signal_entity_core.cpp b/interfaces/kits/js/src/mod_fs/class_tasksignal/task_signal_entity_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85dd60f91181d3f0d9bbe5030731c9cd3dd103b3 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_tasksignal/task_signal_entity_core.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 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 "task_signal_entity_core.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +TaskSignalEntityCore::~TaskSignalEntityCore() {} + +void TaskSignalEntityCore::OnCancel() +{ + if (!callbackContextCore_) { + return; + } + + callbackContextCore_->cb(taskSignal_->filePath_); +} +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/class_tasksignal/task_signal_entity_core.h b/interfaces/kits/js/src/mod_fs/class_tasksignal/task_signal_entity_core.h new file mode 100644 index 0000000000000000000000000000000000000000..c301442c797799d4478a5829ad1241360c25a2cf --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/class_tasksignal/task_signal_entity_core.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024 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 FILEMANAGEMENT_FILE_API_TASK_SIGNAL_ENTITY_CORE_H +#define FILEMANAGEMENT_FILE_API_TASK_SIGNAL_ENTITY_CORE_H + +#include "task_signal.h" +#include "task_signal_listener.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace DistributedFS::ModuleTaskSignal; +typedef std::function TaskSignalCb; + +class CallbackContextCore { +public: + explicit CallbackContextCore(TaskSignalCb cb) : cb(cb) {} + ~CallbackContextCore() = default; + + TaskSignalCb cb; + std::string filePath_; +}; + +class TaskSignalEntityCore : public TaskSignalListener { +public: + TaskSignalEntityCore() = default; + ~TaskSignalEntityCore() override; + void OnCancel() override; + + std::shared_ptr taskSignal_ = nullptr; + std::shared_ptr callbackContextCore_ = nullptr; +}; +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // FILEMANAGEMENT_FILE_API_TASK_SIGNAL_ENTITY_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/fs_utils.cpp b/interfaces/kits/js/src/mod_fs/fs_utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2f42691023ab6e189cdfa1b58d5690e6e9c94ba --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/fs_utils.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025 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 "fs_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +namespace { +const vector PUBLIC_DIR_PATHS = { "/Documents" }; +} + +tuple FsUtils::GetActualLen(size_t bufLen, size_t bufOff, const optional &length) +{ + size_t retLen = bufLen - bufOff; + + if (length.has_value()) { + int64_t opLength = length.value(); + if (opLength < 0 || static_cast(opLength) > retLen) { + HILOGE("Invalid option.length"); + return { false, 0 }; + } + retLen = static_cast(opLength); + } + return { true, retLen }; +} + +uint32_t FsUtils::ConvertFlags(const uint32_t &flags) +{ + // default value is usrReadOnly 00 + uint32_t flagsABI = 0; + flagsABI |= ((flags & USR_WRITE_ONLY) == USR_WRITE_ONLY) ? WRONLY : 0; + flagsABI |= ((flags & USR_RDWR) == USR_RDWR) ? RDWR : 0; + flagsABI |= ((flags & USR_CREATE) == USR_CREATE) ? CREATE : 0; + flagsABI |= ((flags & USR_TRUNC) == USR_TRUNC) ? TRUNC : 0; + flagsABI |= ((flags & USR_APPEND) == USR_APPEND) ? APPEND : 0; + flagsABI |= ((flags & USR_NONBLOCK) == USR_NONBLOCK) ? NONBLOCK : 0; + flagsABI |= ((flags & USR_DIRECTORY) == USR_DIRECTORY) ? DIRECTORY : 0; + flagsABI |= ((flags & USR_NOFOLLOW) == USR_NOFOLLOW) ? NOFOLLOW : 0; + flagsABI |= ((flags & USR_SYNC) == USR_SYNC) ? SYNC : 0; + return flagsABI; +} + +void FsUtils::FsReqCleanup(uv_fs_t *req) +{ + uv_fs_req_cleanup(req); + if (req) { + delete req; + req = nullptr; + } +} + +string FsUtils::GetModeFromFlags(const uint32_t &flags) +{ + const string readMode = "r"; + const string writeMode = "w"; + const string appendMode = "a"; + const string truncMode = "t"; + string mode = readMode; + mode += (((flags & O_RDWR) == O_RDWR) ? writeMode : ""); + mode = (((flags & O_WRONLY) == O_WRONLY) ? writeMode : mode); + if (mode != readMode) { + mode += ((flags & O_TRUNC) ? truncMode : ""); + mode += ((flags & O_APPEND) ? appendMode : ""); + } + return mode; +} + +bool FsUtils::CheckPublicDirPath(const string &sandboxPath) +{ + for (const string &path : PUBLIC_DIR_PATHS) { + if (sandboxPath.find(path) == 0) { + return true; + } + } + return false; +} + +string FsUtils::Decode(const string &uri) +{ + ostringstream outPutStream; + const int32_t encodeLen = 2; + size_t index = 0; + while (index < uri.length()) { + if (uri[index] == '%') { + int hex = 0; + istringstream inputStream(uri.substr(index + 1, encodeLen)); + inputStream >> hex >> hex; + outPutStream << static_cast(hex); + index += encodeLen + 1; + } else { + outPutStream << uri[index]; + index++; + } + } + + return outPutStream.str(); +} + +} // namespace OHOS::FileManagement::ModuleFileIO diff --git a/interfaces/kits/js/src/mod_fs/fs_utils.h b/interfaces/kits/js/src/mod_fs/fs_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..de4b9af4dc213f534c4adb8c37fbcccef82974ea --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/fs_utils.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_FS_UTILS_H +#define FILEMANAGEMENT_FS_UTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "fd_guard.h" +#include "uv.h" + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +#include "iremote_broker.h" +#endif + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +constexpr int32_t RDONLY = UV_FS_O_RDONLY; +constexpr int32_t WRONLY = UV_FS_O_WRONLY; +constexpr int32_t RDWR = UV_FS_O_RDWR; +constexpr int32_t CREATE = UV_FS_O_CREAT; +constexpr int32_t TRUNC = UV_FS_O_TRUNC; +constexpr int32_t APPEND = UV_FS_O_APPEND; +constexpr int32_t NONBLOCK = UV_FS_O_NONBLOCK; +constexpr int32_t DIRECTORY = UV_FS_O_DIRECTORY; +constexpr int32_t NOFOLLOW = UV_FS_O_NOFOLLOW; +constexpr int32_t SYNC = UV_FS_O_SYNC; + +constexpr uint32_t MODE_EXIST = 00; +constexpr uint32_t MODE_WRITE = 02; +constexpr uint32_t MODE_READ = 04; +constexpr uint32_t MODE_READ_WRITE = 06; + +constexpr uint32_t USR_READ_ONLY = 00; +constexpr uint32_t USR_WRITE_ONLY = 01; +constexpr uint32_t USR_RDWR = 02; +constexpr uint32_t USR_CREATE = 0100; +constexpr uint32_t USR_TRUNC = 01000; +constexpr uint32_t USR_APPEND = 02000; +constexpr uint32_t USR_NONBLOCK = 04000; +constexpr uint32_t USR_DIRECTORY = 0200000; +constexpr uint32_t USR_NOFOLLOW = 0400000; +constexpr uint32_t USR_SYNC = 04010000; + +const double NS = 1e9; +const double MS = 1e3; + +struct FileInfo { + bool isPath = false; + unique_ptr path = { nullptr }; + unique_ptr fdg = { nullptr }; +}; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +class FileIoToken : public IRemoteBroker { +public: + DECLARE_INTERFACE_DESCRIPTOR(u"ohos.fileio.open"); + + FileIoToken() = default; + virtual ~FileIoToken() noexcept = default; +}; +#endif + +class FsUtils { +public: + static tuple GetActualLen(size_t bufLen, size_t bufOff, const optional &length = nullopt); + static uint32_t ConvertFlags(const uint32_t &flags); + static void FsReqCleanup(uv_fs_t *req); + static string GetModeFromFlags(const uint32_t &flags); + static bool CheckPublicDirPath(const string &sandboxPath); + static string Decode(const string &uri); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // FILEMANAGEMENT_FS_UTILS_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/access_core.cpp b/interfaces/kits/js/src/mod_fs/properties/access_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d97f4aa80452f316e0cc85ba660509004c9e544e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/access_core.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2025 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 "access_core.h" + +#include + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +#include + +#include "bundle_mgr_proxy.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "rust_file.h" +#include "system_ability_definition.h" + +#endif + +#ifdef FILE_API_TRACE +#include "hitrace_meter.h" +#endif + +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace AppExecFwk; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +const string CLOUDDISK_FILE_PREFIX = "/data/storage/el2/cloud"; +const string DISTRIBUTED_FILE_PREFIX = "/data/storage/el2/distributedfiles"; +const string PACKAGE_NAME_FLAG = ""; +const string USER_ID_FLAG = ""; +const string PHYSICAL_PATH_PREFIX = "/mnt/hmdfs//account/device_view/local/data/"; +const string CLOUD_FILE_LOCATION = "user.cloud.location"; +const char POSITION_LOCAL = '1'; +const char POSITION_BOTH = '3'; +const int BASE_USER_RANGE = 200000; +#endif + +static int UvAccess(const string &path, int mode) +{ + std::unique_ptr access_req = {new uv_fs_t, FsUtils::FsReqCleanup}; + if (!access_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + return uv_fs_access(nullptr, access_req.get(), path.c_str(), mode, nullptr); +} + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +static bool IsCloudOrDistributedFilePath(const string &path) +{ + return path.find(CLOUDDISK_FILE_PREFIX) == 0 || path.find(DISTRIBUTED_FILE_PREFIX) == 0; +} + +static int GetCurrentUserId() +{ + int uid = IPCSkeleton::GetCallingUid(); + int userId = uid / BASE_USER_RANGE; + return userId; +} + +static sptr GetBundleMgrProxy() +{ + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityManager) { + HILOGE("fail to get system ability mgr"); + return nullptr; + } + sptr remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + if (!remoteObject) { + HILOGE("fail to get bundle manager proxy"); + return nullptr; + } + + return iface_cast(remoteObject); +} + +static string GetSelfBundleName() +{ + sptr bundleMgrProxy = GetBundleMgrProxy(); + if (!bundleMgrProxy) { + HILOGE("bundleMgrProxy is nullptr"); + return ""; + } + BundleInfo bundleInfo; + auto ret = bundleMgrProxy->GetBundleInfoForSelf(0, bundleInfo); + if (ret != 0) { + HILOGE("bundleName get fail"); + return ""; + } + return bundleInfo.name; +} + +static int HandleLocalCheck(const string &path, int mode) +{ + // check if the file of /data/storage/el2/cloud is on the local + if (path.find(CLOUDDISK_FILE_PREFIX) == 0) { + char val[2] = {'\0'}; + if (getxattr(path.c_str(), CLOUD_FILE_LOCATION.c_str(), val, sizeof(val)) < 0) { + HILOGI("get cloud file location fail, err: %{public}d", errno); + return errno; + } + if (val[0] == POSITION_LOCAL || val[0] == POSITION_BOTH) { + return 0; + } + return ENOENT; + } + // check if the distributed file of /data/storage/el2/distributedfiles is on the local, + // convert into physical path(/mnt/hmdfs//account/device_view/local/data/) and check + if (path.find(DISTRIBUTED_FILE_PREFIX) == 0) { + int userId = GetCurrentUserId(); + string bundleName = GetSelfBundleName(); + string relativePath = path.substr(DISTRIBUTED_FILE_PREFIX.length()); + string physicalPath = PHYSICAL_PATH_PREFIX + relativePath; + physicalPath.replace(physicalPath.find(USER_ID_FLAG), USER_ID_FLAG.length(), to_string(userId)); + physicalPath.replace(physicalPath.find(PACKAGE_NAME_FLAG), PACKAGE_NAME_FLAG.length(), bundleName); + + return UvAccess(physicalPath, mode); + } + + return ENOENT; +} +#endif + +static int Access(const string &path, int mode, int flag = DEFAULT_FLAG) +{ +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + if (flag == LOCAL_FLAG && IsCloudOrDistributedFilePath(path)) { + return HandleLocalCheck(path, mode); + } +#endif + return UvAccess(path, mode); +} + +static int GetMode(const std::optional &modeOpt, bool *hasMode) +{ + if (modeOpt.has_value()) { + int mode = static_cast(modeOpt.value()); + *hasMode = true; + if ((static_cast(mode) & 0x06) == static_cast(mode)) { + return mode; + } + } + + return -1; +} + +static bool ValidAccessArgs(const std::string &path, const std::optional &modeOpt, + int &finalMode, int &flag) +{ + if (path.empty()) { + HILOGE("Invalid path"); + return false; + } + bool hasMode = false; + int mode = GetMode(modeOpt, &hasMode); + if (mode < 0 && hasMode) { + HILOGE("Invalid mode"); + return false; + } + finalMode = hasMode ? mode : 0; + flag = DEFAULT_FLAG; + return true; +} + +FsResult AccessCore::DoAccess(const std::string& path, const std::optional &mode) +{ + int finalMode = 0; + int flag = DEFAULT_FLAG; + if (!ValidAccessArgs(path, mode, finalMode, flag)) { + return FsResult::Error(EINVAL); + } + int ret = Access(path, finalMode, flag); + if (ret < 0 && (std::string_view(uv_err_name(ret)) != "ENOENT")) { + HILOGE("Failed to access file by path"); + return FsResult::Error(ret); + } + bool isAccess = (ret == 0); + return FsResult::Success(isAccess); +} + +FsResult AccessCore::DoAccess(const std::string& path, const AccessModeType &mode, const AccessFlag &flag) +{ + int finalMode = static_cast(mode); + int finalFlag = static_cast(flag); + if (!ValidAccessArgs(path, std::make_optional(mode), finalMode, finalFlag)) { + return FsResult::Error(EINVAL); + } + int ret = Access(path, finalMode, finalFlag); + if (ret < 0 && (std::string_view(uv_err_name(ret)) != "ENOENT")) { + HILOGE("Failed to access file by path"); + return FsResult::Error(ret); + } + bool isAccess = (ret == 0); + return FsResult::Success(isAccess); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/access_core.h b/interfaces/kits/js/src/mod_fs/properties/access_core.h new file mode 100644 index 0000000000000000000000000000000000000000..0a6f9e1b2f7776e5b6af5db1c12b773e0d9113bb --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/access_core.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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_ACCESS_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ACCESS_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +enum class AccessModeType { ERROR = -1, EXIST = 0, WRITE = 2, READ = 4, READ_WRITE = 6 }; + +enum AccessFlag : int32_t { + DEFAULT_FLAG = -1, + LOCAL_FLAG, +}; + +class AccessCore { +public: + inline static const string className_ = "__properities__"; + + static FsResult DoAccess(const string &path, const optional &mode = nullopt); + static FsResult DoAccess(const string &path, const AccessModeType &mode, const AccessFlag &flag); +}; + +constexpr int DIR_DEFAULT_PERM = 0770; +const string PROCEDURE_ACCESS_NAME = "FileIOAccess"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ACCESS_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/access_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/access_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..329e116231db924a7a676180d4d20c25f63f8eca --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/access_ani.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025 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 "access_ani.h" + +#include "access_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +static constexpr int EXIST_INDEX = 0; +static constexpr int WRITE_INDEX = 2; +static constexpr int READ_INDEX = 4; +static constexpr int READ_WRITE_INDEX = 6; + +static constexpr int LOCAL_INDEX = 0; + +AccessModeType ToAccessModeType(int32_t mode_index) +{ + switch (mode_index) { + case EXIST_INDEX: + return AccessModeType::EXIST; + case WRITE_INDEX: + return AccessModeType::WRITE; + case READ_INDEX: + return AccessModeType::READ; + case READ_WRITE_INDEX: + return AccessModeType::READ_WRITE; + default: + return AccessModeType::ERROR; + } +} + +std::optional OptToAccessModeType(const std::optional &mode_index) +{ + if (!mode_index.has_value()) { + return std::nullopt; + } + return ToAccessModeType(mode_index.value()); +} + +AccessFlag ToAccessFlagType(int32_t flag_index) +{ + switch (flag_index) { + case LOCAL_INDEX: + return AccessFlag::LOCAL_FLAG; + default: + return AccessFlag::DEFAULT_FLAG; + } +} + +std::optional OptToAccessFlagType(const std::optional &flag_index) +{ + if (!flag_index.has_value()) { + return std::nullopt; + } + return ToAccessFlagType(flag_index.value()); +} + +ani_boolean AccessAni::AccessSync3( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_enum_item mode, ani_enum_item flag) +{ + ani_boolean ret = 0; + auto [succPath, pathStr] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return ret; + } + + auto [succMode, modeOp] = TypeConverter::EnumToInt32(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return ret; + } + auto modeType = OptToAccessModeType(modeOp); + + auto [succFlag, flagOpt] = TypeConverter::EnumToInt32(env, flag); + if (!succFlag) { + HILOGE("Invalid flag"); + ErrorHandler::Throw(env, EINVAL); + return ret; + } + auto flagType = OptToAccessFlagType(flagOpt); + + FsResult fsRet = FsResult::Error(UNKNOWN_ERR); + if (flagOpt == std::nullopt) { + fsRet = AccessCore::DoAccess(pathStr, modeType); + } else { + fsRet = AccessCore::DoAccess(pathStr, modeType.value(), flagType.value()); + } + + if (!fsRet.IsSuccess()) { + HILOGE("DoAccess failed"); + const auto &err = fsRet.GetError(); + ErrorHandler::Throw(env, err); + return false; + } + return fsRet.GetData().value(); +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/access_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/access_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..2dea25bda4d221d2460c6438488e210eae2b1b55 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/access_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_ACCESS_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_ACCESS_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class AccessAni final { +public: + static ani_boolean AccessSync3( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_enum_item mode, ani_enum_item flag); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_ACCESS_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/close_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/close_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f49ccf2f256d3f877b6970f70c7c27e698fcd57e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/close_ani.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025 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 "close_ani.h" + +#include + +#include "close_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +tuple ParseFd(ani_env *env, ani_object obj) +{ + int32_t result = -1; + ani_class IntClass; + env->FindClass("Lstd/core/Double;", &IntClass); + ani_boolean isInt; + env->Object_InstanceOf(obj, IntClass, &isInt); + if (isInt) { + ani_int fd; + if (ANI_OK != env->Object_CallMethodByName_Int(obj, "intValue", nullptr, &fd)) { + HILOGE("Get fd value failed"); + return { false, result }; + } + result = static_cast(fd); + return { true, result }; + } + + ani_class FileClass; + env->FindClass("L@ohos/file/fs/FileInner;", &FileClass); + ani_boolean isFile; + env->Object_InstanceOf(obj, FileClass, &isFile); + if (isFile) { + ani_double fd; + if (ANI_OK != env->Object_GetPropertyByName_Double(obj, "fd", &fd)) { + HILOGE("Get fd in class file failed"); + return { false, result }; + } + result = static_cast(fd); + return { true, result }; + } + HILOGE("Invalid fd type"); + return { false, result }; +} + +void CloseAni::CloseSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_object obj) +{ + auto [succ, fd] = ParseFd(env, obj); + if (!succ) { + HILOGE("Parse fd argument failed"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = CloseCore::DoClose(fd); + if (!ret.IsSuccess()) { + HILOGE("Close %d failed", fd); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/close_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/close_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..cd2715ebeeafc532cce408b4d358d34d8e17adfa --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/close_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_CLOSE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CLOSE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class CloseAni final { +public: + static void CloseSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_object obj); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CLOSE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/copy_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/copy_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f9b713c328cf0f9e8fef23f1eef5d2f60fc0116 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/copy_ani.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025 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 "copy_ani.h" + +#include "ani_helper.h" +#include "copy_core.h" +#include "error_handler.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +static void SetProgressListenerCb(ani_env *env, ani_ref &callback, CopyOptions &opts) +{ + ani_vm *vm = nullptr; + env->GetVM(&vm); + + opts.listenerCb = [vm, &callback](uint64_t progressSize, uint64_t totalSize) -> void { + ani_status ret; + ani_object progress = {}; + static const char *className = "L@ohos/file/fs/ProgressInner;"; + ani_class cls; + + auto env = AniHelper::GetThreadEnv(vm); + if (env == nullptr) { + HILOGE("failed to GetThreadEnv"); + return; + } + + if (progressSize > MAX_VALUE || totalSize > MAX_VALUE) { + HILOGE("progressSize or totalSize exceed MAX_VALUE: %{private}llu %{private}llu", progressSize, totalSize); + } + + if ((ret = env->FindClass(className, &cls)) != ANI_OK) { + HILOGE("Not found %{private}s, err: %{private}d", className, ret); + return; + } + + ani_method ctor; + if ((ret = env->Class_FindMethod(cls, "", "DD:V", &ctor)) != ANI_OK) { + HILOGE("Not found ctor, err: %{private}d", ret); + return; + } + + if ((ret = env->Object_New(cls, ctor, &progress, ani_double(static_cast(progressSize)), + ani_double(static_cast(totalSize)))) != ANI_OK) { + HILOGE("New ProgressInner Fail, err: %{private}d", ret); + return; + } + + std::vector vec; + vec.push_back(progress); + ani_ref result; + ret = env->FunctionalObject_Call(static_cast(callback), vec.size(), vec.data(), &result); + if (ret != ANI_OK) { + HILOGE("FunctionalObject_Call, err: %{private}d", ret); + return; + } + }; +} + +static bool SetTaskSignal(ani_env *env, ani_ref ©Signal, CopyOptions &opts) +{ + ani_status ret; + auto taskSignalEntityCore = CreateSharedPtr(); + if (taskSignalEntityCore == nullptr) { + HILOGE("Failed to request heap memory."); + return false; + } + + ret = env->Object_SetFieldByName_Long(static_cast(copySignal), "nativeTaskSignal", + reinterpret_cast(taskSignalEntityCore.get())); + if (ret != ANI_OK) { + HILOGE("Object set nativeTaskSignal err: %{private}d", ret); + return false; + } + + taskSignalEntityCore->taskSignal_ = std::make_shared(); + opts.taskSignalEntityCore = move(taskSignalEntityCore); + + return true; +} + +static tuple> ParseOptions(ani_env *env, ani_ref &cb, ani_object &options) +{ + ani_boolean isUndefined; + ani_status ret; + env->Reference_IsUndefined(options, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + CopyOptions opts; + ani_ref prog; + if ((ret = env->Object_GetPropertyByName_Ref(options, "progressListener", &prog)) != ANI_OK) { + HILOGE("Object_GetPropertyByName_Ref progressListener, err: %{private}d", ret); + return { false, nullopt }; + } + env->Reference_IsUndefined(prog, &isUndefined); + if (!isUndefined) { + env->GlobalReference_Create(prog, &cb); + SetProgressListenerCb(env, cb, opts); + } + + ani_ref signal; + if ((ret = env->Object_GetPropertyByName_Ref(options, "copySignal", &signal)) != ANI_OK) { + HILOGE("Object_GetPropertyByName_Ref copySignal, err: %{private}d", ret); + return { false, nullopt }; + } + env->Reference_IsUndefined(signal, &isUndefined); + if (!isUndefined) { + if (!SetTaskSignal(env, signal, opts)) { + return { false, nullopt }; + } + } + + return { true, make_optional(move(opts)) }; +} + +void CopyAni::CopySync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string srcUri, ani_string destUri, ani_object options) +{ + auto [succSrc, src] = TypeConverter::ToUTF8String(env, srcUri); + auto [succDest, dest] = TypeConverter::ToUTF8String(env, destUri); + if (!succSrc || !succDest) { + HILOGE("The first/second argument requires filepath"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + ani_ref cb; + auto [succOpts, opts] = ParseOptions(env, cb, options); + if (!succOpts) { + HILOGE("Failed to parse opts"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = CopyCore::DoCopy(src, dest, opts); + if (opts.has_value() && opts->listenerCb != nullptr) { + env->GlobalReference_Delete(cb); + } + if (!ret.IsSuccess()) { + HILOGE("DoCopy failed!"); + const FsError &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/copy_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/copy_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..fbbcf9d08f1ed635028dd993e03f7bddfd36f00e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/copy_ani.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_ANI_COPY_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_COPY_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class CopyAni final { +public: + static void CopySync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string srcUri, ani_string destUri, ani_object options); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_COPY_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/copy_file_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/copy_file_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51e30f4de0053763d7b6c0d812c6c4d1b1eaf554 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/copy_file_ani.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 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 "copy_file_ani.h" + +#include "copy_file_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +void CopyFileAni::CopyFileSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_object src, ani_object dest, ani_object mode) +{ + auto [succSrc, srcFile] = TypeConverter::ToFileInfo(env, src); + auto [succDest, destFile] = TypeConverter::ToFileInfo(env, dest); + if (!succSrc || !succDest) { + HILOGE("The first/second argument requires filepath/fd"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [succMode, optMode] = TypeConverter::ToOptionalInt32(env, mode); + if (!succMode) { + HILOGE("Failed to convert mode to int32"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = CopyFileCore::DoCopyFile(srcFile, destFile, optMode); + if (!ret.IsSuccess()) { + HILOGE("DoCopyFile failed!"); + const FsError &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/copy_file_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/copy_file_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..ce5c5c168a4b87d0e222682c541cffca11977d6f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/copy_file_ani.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_ANI_COPY_FILE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_COPY_FILE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class CopyFileAni final { +public: + static void CopyFileSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_object src, ani_object dest, ani_object mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_COPY_FILE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_randomaccessfile_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/create_randomaccessfile_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5760e6e4bc48f0db8978fde5ac5e10cd92cf8642 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_randomaccessfile_ani.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2025 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_ani.h" + +#include "ani_helper.h" +#include "create_randomaccessfile_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +static ani_object Wrap(ani_env *env, const FsRandomAccessFile *rafFile) +{ + static const char *className = "L@ohos/file/fs/RandomAccessFileInner;"; + ani_class cls; + if (ANI_OK != env->FindClass(className, &cls)) { + HILOGE("Cannot find class %s", className); + return nullptr; + } + ani_method ctor; + if (ANI_OK != env->Class_FindMethod(cls, "", "J:V", &ctor)) { + HILOGE("Cannot find constructor method for class %s", className); + return nullptr; + } + ani_long ptr = static_cast(reinterpret_cast(rafFile)); + ani_object obj; + if (ANI_OK != env->Object_New(cls, ctor, &obj, ptr)) { + HILOGE("New %s obj Failed!", className); + return nullptr; + } + const auto &fdRet = rafFile->GetFD(); + if (!fdRet.IsSuccess()) { + HILOGE("GetFD Failed!"); + return nullptr; + } + const auto &fd = fdRet.GetData().value(); + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "fd", static_cast(fd))) { + HILOGE("Set fd field value failed!"); + return nullptr; + } + const auto &fpRet = rafFile->GetFPointer(); + if (!fpRet.IsSuccess()) { + HILOGE("GetFPointer Failed!"); + return nullptr; + } + const auto &fp = fpRet.GetData().value(); + if (ANI_OK != AniHelper::SetPropertyValue(env, cls, obj, "filePointer", static_cast(fp))) { + HILOGE("Set fp field value failed!"); + return nullptr; + } + return obj; +} + +static tuple JudgeFile(ani_env *env, ani_object obj) +{ + ani_class stringClass; + env->FindClass("Lstd/core/String;", &stringClass); + ani_boolean isString = false; + env->Object_InstanceOf(obj, stringClass, &isString); + if (isString) { + return { true, true }; + } + + ani_class fileClass; + env->FindClass("L@ohos/file/fs/FileInner;", &fileClass); + ani_boolean isFile = false; + env->Object_InstanceOf(obj, fileClass, &isFile); + if (isFile) { + return { true, false }; + } + HILOGE("Invalid file type"); + return { false, false }; +} + +static tuple> ToRafOptions(ani_env *env, ani_object obj) +{ + RandomAccessFileOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succStart, start] = AniHelper::ParseInt64Option(env, obj, "start"); + if (!succStart) { + HILOGE("Illegal option.start parameter"); + return { false, nullopt }; + } + options.start = start; + + auto [succEnd, end] = AniHelper::ParseInt64Option(env, obj, "end"); + if (!succEnd) { + HILOGE("Illegal option.end parameter"); + return { false, nullopt }; + } + options.end = end; + + return { true, make_optional(move(options)) }; +} + +static ani_object CreateRandomAccessFileByString(ani_env *env, ani_object file, ani_object mode, + optional op) +{ + auto [succPath, path] = TypeConverter::ToUTF8String(env, static_cast(file)); + if (!succPath) { + HILOGE("Parse file path failed"); + return nullptr; + } + auto [succMode, modeOp] = TypeConverter::ToOptionalInt32(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + FsResult ret = CreateRandomAccessFileCore::DoCreateRandomAccessFile(path, modeOp, op); + if (!ret.IsSuccess()) { + HILOGE("CreateRandomAccessFile failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + const FsRandomAccessFile *refFile = ret.GetData().value(); + auto result = Wrap(env, move(refFile)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +ani_object CreateRandomAccessFileAni::CreateRandomAccessFileSync(ani_env *env, [[maybe_unused]] ani_class clazz, + ani_object file, ani_object mode, ani_object options) +{ + auto [succOp, op] = ToRafOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succ, isPath] = JudgeFile(env, file); + if (!succ) { + HILOGE("Judge file argument failed"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + if (isPath) { + return CreateRandomAccessFileByString(env, file, mode, op); + } else { + ani_double fdOp; + if (ANI_OK != env->Object_GetPropertyByName_Double(file, "fd", &fdOp)) { + HILOGE("Get fd in class file failed"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + int32_t fd = static_cast(fdOp); + FsResult ret = CreateRandomAccessFileCore::DoCreateRandomAccessFile(fd, op); + if (!ret.IsSuccess()) { + HILOGE("CreateRandomAccessFile failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + const FsRandomAccessFile *refFile = ret.GetData().value(); + auto result = Wrap(env, move(refFile)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_randomaccessfile_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/create_randomaccessfile_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..eb794059659181dfc0edb82d7373ba42b2257f54 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_randomaccessfile_ani.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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_ANI_CREATE_RANDOMACCESSFILE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_CREATE_RANDOMACCESSFILE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class CreateRandomAccessFileAni final { +public: + static ani_object CreateRandomAccessFileSync(ani_env *env, [[maybe_unused]] ani_class clazz, + ani_object file, ani_object mode, ani_object options); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_CREATE_RANDOMACCESSFILE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b8fd35e59b2a16b0ba877b96c815d090b6b07d74 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2025 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_ani.h" + +#include "create_stream_core.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "stream_wrapper.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object CreateStreamAni::CreateStreamSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string mode) +{ + auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succMode, openMode] = TypeConverter::ToUTF8String(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + FsResult ret = CreateStreamCore::DoCreateStream(srcPath, openMode); + if (!ret.IsSuccess()) { + HILOGE("create stream failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const FsStream *stream = ret.GetData().value(); + auto result = StreamWrapper::Wrap(env, move(stream)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..2052b6b4d07e5705439f08de2b3c401bf3febfdb --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/create_stream_ani.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class CreateStreamAni final { +public: + static ani_object CreateStreamSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/dup_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/dup_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9158f077c6e14d9eba133634486e0c4c941dbf36 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/dup_ani.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2025 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 "dup_ani.h" + +#include "ani_helper.h" +#include "dup_core.h" +#include "error_handler.h" +#include "file_wrapper.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object DupAni::Dup(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd) +{ + FsResult ret = DupCore::DoDup(static_cast(fd)); + if (!ret.IsSuccess()) { + HILOGE("Dup file failed"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + const FsFile *file = ret.GetData().value(); + auto result = FileWrapper::Wrap(env, move(file)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/dup_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/dup_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..8f943ddb2f4cb475f5e4b85bbd33dc3cf158e801 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/dup_ani.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_DUP_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_DUP_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class DupAni final { +public: + static ani_object Dup(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_DUP_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/fdatasync_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/fdatasync_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7ce4a8bfc81fd4fb130d5819365ba492ab186f3f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/fdatasync_ani.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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 "fdatasync_ani.h" + +#include + +#include "error_handler.h" +#include "fdatasync_core.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void FDataSyncAni::FDataSyncSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd) +{ + auto ret = FDataSyncCore::DoFDataSync(static_cast(fd)); + if (!ret.IsSuccess()) { + HILOGE("Fdatasync failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/fdatasync_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/fdatasync_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..ce0b8326125c526b1fc78de7bb0aaba22c67aa71 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/fdatasync_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_ANI_FDATASYNC_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_FDATASYNC_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class FDataSyncAni final { +public: + static void FDataSyncSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_FDATASYNC_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/fdopen_stream_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/fdopen_stream_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bc6e8d27415910d8118119f59264400d58283398 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/fdopen_stream_ani.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 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_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fdopen_stream_core.h" +#include "stream_wrapper.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object FdopenStreamAni::FdopenStreamSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_string mode) +{ + auto [succMode, openMode] = TypeConverter::ToUTF8String(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + FsResult ret = FdopenStreamCore::DoFdopenStream(static_cast(fd), openMode); + if (!ret.IsSuccess()) { + HILOGE("fdopen stream failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const FsStream *stream = ret.GetData().value(); + auto result = StreamWrapper::Wrap(env, move(stream)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/fdopen_stream_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/fdopen_stream_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..81f0fde31b630e1e90a6243ba335cd8b5c254215 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/fdopen_stream_ani.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDOPEN_STREAM_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class FdopenStreamAni final { +public: + static ani_object FdopenStreamSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_string mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDOPEN_STREAM_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/fsync_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/fsync_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2680914fc313466b722d22ffbe162118d603b6f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/fsync_ani.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 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 "fsync_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "fsync_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +void FsyncAni::FsyncSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd) +{ + auto ret = FsyncCore::DoFsync(static_cast(fd)); + if (!ret.IsSuccess()) { + HILOGE("DoFsync failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/fsync_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/fsync_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..ad9d936fe9c5a6cb1b6bf1a536a91d99bc599642 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/fsync_ani.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_ANI_FSYNC_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_FSYNC_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class FsyncAni final { +public: + static void FsyncSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_FSYNC_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/listfile_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/listfile_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8540848a3f65a064ee14969ddb619248aeb6c414 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/listfile_ani.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2025 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 "listfile_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "listfile_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +tuple ParseBooleanParam(ani_env *env, ani_object obj, string tag) +{ + ani_ref bool_ref; + ani_boolean isUndefined; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &bool_ref)) { + return { false, false }; + } + env->Reference_IsUndefined(bool_ref, &isUndefined); + if (isUndefined) { + return { true, false }; + } + ani_boolean bool_ref_res; + if (ANI_OK != env->Object_CallMethodByName_Boolean( + static_cast(bool_ref), "unboxed", ":Z", &bool_ref_res)) { + return { false, false }; + } + return { true, static_cast(bool_ref_res) }; +} + +tuple ParseIntParam(ani_env *env, ani_object obj, string tag) +{ + int result = 0; + ani_boolean isUndefined; + ani_ref result_ref; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &result_ref)) { + return { false, result }; + } + env->Reference_IsUndefined(result_ref, &isUndefined); + if (isUndefined) { + return { true, result }; + } + ani_int result_ref_res; + if (ANI_OK != env->Object_CallMethodByName_Int( + static_cast(result_ref), "intValue", nullptr, &result_ref_res)) { + result = -1; + return { false, result }; + } + result = static_cast(result_ref_res); + return { true, result }; +} + +tuple> ParseDoubleParam(ani_env *env, ani_object obj, string tag) +{ + ani_boolean isUndefined; + ani_ref result_ref; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &result_ref)) { + return { false, nullopt }; + } + env->Reference_IsUndefined(result_ref, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + ani_double result_ref_res; + if (ANI_OK != env->Object_CallMethodByName_Double( + static_cast(result_ref), "doubleValue", nullptr, &result_ref_res)) { + return { false, nullopt }; + } + double result = static_cast(result_ref_res); + return { true, make_optional(result) }; +} + +tuple>> ParseArrayString(ani_env *env, ani_object obj, string tag) +{ + ani_boolean isUndefined; + ani_ref result_ref; + vector strings; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, tag.c_str(), &result_ref)) { + return { false, nullopt }; + } + env->Reference_IsUndefined(result_ref, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + ani_double length; + if (ANI_OK != env->Object_GetPropertyByName_Double( + static_cast(result_ref), "length", &length) || length == 0) { + return { false, nullopt }; + } + for (int i = 0; i < int(length); i++) { + ani_ref stringEntryRef; + if (ANI_OK != env->Object_CallMethodByName_Ref( + static_cast(result_ref), "$_get", "I:Lstd/core/Object;", &stringEntryRef, (ani_int)i)) { + return { false, nullopt }; + } + auto [succ, tmp] = TypeConverter::ToUTF8String(env, static_cast(stringEntryRef)); + if (!succ) { + return { false, nullopt }; + } + strings.emplace_back(tmp); + } + return { true, make_optional>(move(strings)) }; +} + +tuple> ParseFilter(ani_env *env, ani_object obj) +{ + FsFileFilter filter; + + auto [succfileSizeOver, fileSizeOver] = ParseIntParam(env, obj, "fileSizeOver"); + if (!succfileSizeOver) { + HILOGE("Illegal option.fileSizeOver parameter"); + return { false, move(filter) }; + } + filter.SetFileSizeOver(fileSizeOver); + + auto [succlastModifiedAfter, lastModifiedAfter] = ParseDoubleParam(env, obj, "lastModifiedAfter"); + if (!succlastModifiedAfter) { + HILOGE("Illegal option.lastModifiedAfter parameter"); + return { false, move(filter) }; + } + filter.SetFileSizeOver(lastModifiedAfter); + + auto [succSuffix, suffix] = ParseArrayString(env, obj, "suffix"); + if (!succSuffix) { + HILOGE("Illegal option.suffix parameter"); + return { false, move(filter) }; + } + filter.SetSuffix(move(suffix)); + + auto [succDisplayName, displayName] = ParseArrayString(env, obj, "displayName"); + if (!succDisplayName) { + HILOGE("Illegal option.displayName parameter"); + return { false, move(filter) }; + } + filter.SetDisplayName(move(displayName)); + + return { true, move(filter) }; +} + +tuple> ParseArgs(ani_env *env, ani_object obj) +{ + FsListFileOptions result; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succRecursion, recursion] = ParseBooleanParam(env, obj, "recursion"); + if (!succRecursion) { + HILOGE("Invalid recursion"); + return { false, nullopt }; + } + result.recursion = recursion; + + auto [succlistNum, listNumRes] = ParseIntParam(env, obj, "listNum"); + if (!succlistNum) { + HILOGE("Invalid listNum"); + return { false, nullopt }; + } + result.listNum = (int)listNumRes; + + ani_ref filter_ref; + if (ANI_OK != env->Object_GetPropertyByName_Ref(obj, "filter", &filter_ref)) { + HILOGE("Invalid filter"); + return { false, nullopt }; + } + env->Reference_IsUndefined(filter_ref, &isUndefined); + if (isUndefined) { + return { true, make_optional(result) }; + } + auto [succFilter, filterFilterClass] = ParseFilter(env, static_cast(filter_ref)); + if (!succFilter) { + HILOGE("Invalid filter"); + return { false, nullopt }; + } + result.filter = move(filterFilterClass); + + return { true, make_optional(result) }; +} + +ani_array_ref ListFileAni::ListFileSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object obj) +{ + auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succOpt, opt] = ParseArgs(env, obj); + if (!succOpt) { + HILOGE("Invalid options Arguments"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = ListFileCore::DoListFile(srcPath, opt); + if (!ret.IsSuccess()) { + HILOGE("DoListFile failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + auto fileList = ret.GetData().value(); + const std::string *strArray = fileList.data(); + auto [succ, result] = TypeConverter::ToAniStringList(env, strArray, fileList.size()); + if (!succ) { + HILOGE("Convert list file result to ani string array failed"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/listfile_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/listfile_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..63ff7731db00fd48fae52f975b7af4f6aa99f99d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/listfile_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_FILELIST_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FILELIST_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ListFileAni final { +public: + static ani_array_ref ListFileSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object obj); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FILELIST_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/lseek_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/lseek_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d689c696ff61f52234c577d46c741d24b5753c0 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/lseek_ani.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 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 "lseek_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "lseek_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; + +optional ParseSeekPos(const optional &whence) +{ + if (!whence.has_value()) { + return nullopt; + } + + return make_optional(static_cast(move(whence.value()))); +} + +ani_double LseekAni::LseekSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_double offset, ani_enum_item whence) +{ + auto [succWhence, whenceOp] = TypeConverter::EnumToInt32(env, whence); + if (!succWhence) { + HILOGE("Invalid whence"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto pos = ParseSeekPos(whenceOp); + + auto ret = LseekCore::DoLseek(static_cast(fd), static_cast(offset), pos); + if (!ret.IsSuccess()) { + HILOGE("DoLseek failed!"); + const FsError &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + + return ani_double(static_cast(ret.GetData().value())); +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/lseek_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/lseek_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..5a7995d799ec2ab6d000304f4b4a1d9589a58177 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/lseek_ani.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_ANI_LSEEK_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_LSEEK_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +class LseekAni final { +public: + static ani_double LseekSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_double offset, ani_enum_item whence); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_LSEEK_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/mkdir_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/mkdir_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a5cd88374fc3bf4e0af4e4eba32427439116a59f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/mkdir_ani.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 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 "mkdir_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "mkdir_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void MkdirkAni::MkdirSync0(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path) +{ + auto [succ, pathStr] = TypeConverter::ToUTF8String(env, path); + if (!succ) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = MkdirCore::DoMkdir(pathStr); + if (!ret.IsSuccess()) { + HILOGE("Mkdir failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +void MkdirkAni::MkdirSync1(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_boolean recursion) +{ + auto [succ, pathStr] = ANI::TypeConverter::ToUTF8String(env, path); + if (!succ) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = MkdirCore::DoMkdir(pathStr, recursion); + if (!ret.IsSuccess()) { + HILOGE("DoMkdir failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/mkdir_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/mkdir_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..8ed780e9619e99f3390c2db0493d9063a9b37e33 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/mkdir_ani.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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_MKDIR_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_MKDIR_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class MkdirkAni final { +public: + static void MkdirSync0(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path); + static void MkdirSync1(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_boolean recursion); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_MKDIR_ANI_H diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42b5a73167eca8dcf6782f61016dea3d1ee24f26 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 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 "mkdtemp_ani.h" + +#include + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "mkdtemp_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +ani_string MkdtempAni::MkdtempSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string prefix) +{ + auto [succPath, prefixPath] = TypeConverter::ToUTF8String(env, prefix); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = MkdtempCore::DoMkdtemp(prefixPath); + if (!ret.IsSuccess()) { + HILOGE("Mkdtemp faild"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const auto &res = ret.GetData().value(); + auto [succ, result] = TypeConverter::ToAniString(env, res); + if (!succ) { + HILOGE("Create ani_string error"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..cda9c8e12905bb44cf86f03a70dc57ce369deed4 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_ANI_MKDTEMP_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MKDTEMP_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class MkdtempAni final { +public: + static ani_string MkdtempSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string prefix); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MKDTEMP_ANI_H diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/move_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/move_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3243554f5f9611e115048faacc029838fde49961 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/move_ani.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 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 "move_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "move_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void MoveAni::MoveFileSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode) +{ + auto [succSrc, srcPath] = TypeConverter::ToUTF8String(env, src); + if (!succSrc) { + HILOGE("Invalid src"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto [succDest, destPath] = TypeConverter::ToUTF8String(env, dest); + if (!succDest) { + HILOGE("Invalid dest"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto [succMode, modeOp] = TypeConverter::ToOptionalInt32(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = MoveCore::DoMove(srcPath, destPath, modeOp); + if (!ret.IsSuccess()) { + HILOGE("Move failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/move_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/move_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..071c35f9fe69f33409a2598274826856ee271e9e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/move_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_MOVE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_MOVE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class MoveAni final { +public: + static void MoveFileSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_MOVE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e2c137c908208a5a760f571fc527ad9ce5529de --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 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 "movedir_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "movedir_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void MoveDirAni::MoveDirSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode) +{ + auto [succSrc, srcPath] = TypeConverter::ToUTF8String(env, src); + auto [succDest, destPath] = TypeConverter::ToUTF8String(env, dest); + if (!succSrc || !succDest) { + HILOGE("The first/second argument requires filepath"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [succMode, optMode] = TypeConverter::ToOptionalInt32(env, mode); + if (!succMode) { + HILOGE("Failed to convert mode to int32"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = MoveDirCore::DoMoveDir(srcPath, destPath, optMode); + if (!ret.fsResult.IsSuccess()) { + HILOGE("DoCopyFile failed!"); + const FsError &err = ret.fsResult.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..bd17504464739b6b56f293980792b1e72b05d858 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_ANI_MOVEDIR_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MOVEDIR_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class MoveDirAni final { +public: + static void MoveDirSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MOVEDIR_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/open_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/open_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68538e0be0086639a7bac8fb7ad2318ab4a6d96e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/open_ani.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 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 "open_ani.h" + +#include "ani_helper.h" +#include "error_handler.h" +#include "file_wrapper.h" +#include "filemgmt_libhilog.h" +#include "open_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_object OpenAni::OpenSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object mode) +{ + auto [succPath, filePath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succMode, modeOp] = TypeConverter::ToOptionalInt32(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + FsResult ret = OpenCore::DoOpen(filePath, modeOp); + if (!ret.IsSuccess()) { + HILOGE("Open failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + const FsFile *file = ret.GetData().value(); + auto result = FileWrapper::Wrap(env, move(file)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/open_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/open_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..765e173bebfa6a625958f8386e8534f1a79f4596 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/open_ani.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_OPEN_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_OPEN_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class OpenAni final { +public: + static ani_object OpenSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_OPEN_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/read_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa5ce2334a35ed1d5973284dea9a9e1eafd42d22 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_ani.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025 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 "read_ani.h" + +#include +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "read_core.h" +#include "type_converter.h" + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +static tuple> ToReadOptions(ani_env *env, ani_object obj) +{ + ReadOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + return { true, make_optional(move(options)) }; +} + +ani_double ReadAni::ReadSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_arraybuffer buffer, ani_object options) +{ + auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [succOp, op] = ToReadOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto ret = ReadCore::DoRead(static_cast(fd), arrayBuffer, op); + if (!ret.IsSuccess()) { + HILOGE("Read file content failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); +} +} // namespace OHOS::FileManagement::ModuleFileIO::ANI \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/read_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..ceec384b48be270170bf14f877680608ad65f1a8 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_ani.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 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_READ_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_READ_ANI_H + +#include + +namespace OHOS::FileManagement::ModuleFileIO::ANI { + +class ReadAni final { +public: + static ani_double ReadSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_arraybuffer buffer, ani_object options); +}; +} // namespace OHOS::FileManagement::ModuleFileIO::ANI +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_READ_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..49b26f784cd53a4650918a391e78cf725a63d9cd --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2025 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 "read_lines_ani.h" + +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "read_lines_core.h" +#include "reader_iterator_ani.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +static tuple> ToReadLinesOptions(ani_env *env, ani_object obj) +{ + Options options; + + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding.value(); + + return { true, make_optional(move(options)) }; +} + +ani_object ReadLinesAni::ReadLinesSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_object options) +{ + auto [succPath, filePath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succMode, opt] = ToReadLinesOptions(env, options); + if (!succMode) { + HILOGE("Invalid options"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + FsResult ret = ReadLinesCore::DoReadLines(filePath, opt); + if (!ret.IsSuccess()) { + HILOGE("Readlines failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + const FsReaderIterator *readerIterator = ret.GetData().value(); + auto result = ReaderIteratorAni::Wrap(env, move(readerIterator)); + if (result == nullptr) { + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..387298f813beb8631a9e49a2a30a196267bd12b6 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_lines_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_READ_LINES_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_READ_LINES_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReadLinesAni final { +public: + static ani_object ReadLinesSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, + ani_object options); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_READ_LINES_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_text_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/read_text_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc733c606ba1779568b5d76350ab0c3f8753bfa7 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_text_ani.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025 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 "read_text_ani.h" + +#include +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "read_text_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleFileIO::ANI; + +static tuple> ToReadTextOptions(ani_env *env, ani_object obj) +{ + ReadTextOptions options; + + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding; + + return { true, make_optional(move(options)) }; +} + +ani_string ReadTextAni::ReadTextSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string filePath, ani_object obj) +{ + auto [succOpt, options] = ToReadTextOptions(env, obj); + if (!succOpt) { + HILOGE("Invalid options"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succPath, path] = TypeConverter::ToUTF8String(env, filePath); + if (!succPath) { + HILOGE("Invalid Path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = ReadTextCore::DoReadText(path, options); + if (!ret.IsSuccess()) { + HILOGE("DoReadText failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const auto &resText = ret.GetData().value(); + string res = std::get<0>(resText); + auto [succ, result] = TypeConverter::ToAniString(env, res); + if (!succ) { + HILOGE("Convert result to ani string failed"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/read_text_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/read_text_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..5d3bf6ad10e9152f9d72f2545e2cc499f1843081 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/read_text_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_READ_TEXT_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_TEXT_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class ReadTextAni final { +public: + static ani_string ReadTextSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string filePath, ani_object obj); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_TEXT_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/rename_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/rename_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b4d762a09bc622fb304ca2f719376e89e39dbb3 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/rename_ani.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025 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 "rename_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "rename_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO; + +void RenameAni::RenameSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string oldPath, ani_string newPath) +{ + auto [succSrcPath, srcPath] = TypeConverter::ToUTF8String(env, oldPath); + if (!succSrcPath) { + HILOGE("Invalid src"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto [succDestPath, destPath] = TypeConverter::ToUTF8String(env, newPath); + if (!succDestPath) { + HILOGE("Invalid dest"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = RenameCore::DoRename(srcPath, destPath); + if (!ret.IsSuccess()) { + HILOGE("DoRename failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/rename_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/rename_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..f2c39cbb0403128bc076044425c793cde6579c91 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/rename_ani.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_ANI_RENAME_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_RENAME_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class RenameAni final { +public: + static void RenameSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string oldPath, ani_string newPath); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_RENAME_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/rmdir_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/rmdir_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..04a4cfa6b2fd2ab944f40b5eb02c1e02b630f4e3 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/rmdir_ani.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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 "rmdir_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "rmdir_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; + +void RmdirAni::RmdirSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path) +{ + auto [succPath, pathStr] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = RmdirentCore::DoRmdirent(pathStr); + if (!ret.IsSuccess()) { + HILOGE("DoRmdirent failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/rmdir_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/rmdir_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..5c7dedc9b30042d9876103e594890c31546e9d99 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/rmdir_ani.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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 RMDIR_ANI_H +#define RMDIR_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class RmdirAni final { +public: + static void RmdirSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // RMDIR_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/symlink_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/symlink_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4cbac513388e666d58b321a6ab77e971b7dc279e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/symlink_ani.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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 "symlink_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "symlink_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void SymlinkAni::SymlinkSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string target, ani_string srcPath) +{ + auto [succTarget, targetPath] = TypeConverter::ToUTF8String(env, target); + if (!succTarget) { + HILOGE("Invalid target"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto [succSrc, src] = TypeConverter::ToUTF8String(env, srcPath); + if (!succSrc) { + HILOGE("Invalid src"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = SymlinkCore::DoSymlink(targetPath, src); + if (!ret.IsSuccess()) { + HILOGE("DoSymlink failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/symlink_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/symlink_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..6ba3abb554ecd244031623959486bcc81f45ea04 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/symlink_ani.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_SYMLINK_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_SYMLINK_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class SymlinkAni final { +public: + static void SymlinkSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string target, ani_string srcPath); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_SYMLINK_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/truncate_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/truncate_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6176d45e123c92a84e679d4b6ccce0bc7f6fc9e3 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/truncate_ani.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 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 "truncate_ani.h" + +#include "error_handler.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "truncate_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void TruncateAni::TruncateSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_object file, ani_object length) +{ + auto [succ, fileinfo] = TypeConverter::ToFileInfo(env, file); + if (!succ) { + HILOGE("Invalid fd/path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [succLen, len] = TypeConverter::ToOptionalInt64(env, length); + if (!succLen) { + HILOGE("Invalid truncate length"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = TruncateCore::DoTruncate(fileinfo, len); + if (!ret.IsSuccess()) { + HILOGE("Truncate failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/truncate_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/truncate_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..896ca7f834ed82ff81fae29a3755f19ec0012088 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/truncate_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_TRUNCATE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_TRUNCATE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class TruncateAni final { +public: + static void TruncateSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_object file, ani_object length); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_TRUNCATE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/unlink_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/unlink_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91a929d134e2b5443fe840fc16441cedf4e45f5e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/unlink_ani.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 "unlink_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" +#include "unlink_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void UnlinkAni::UnlinkSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path) +{ + auto [succ, pathStr] = TypeConverter::ToUTF8String(env, path); + if (!succ) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = UnlinkCore::DoUnlink(pathStr); + if (!ret.IsSuccess()) { + HILOGE("Unlink failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/unlink_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/unlink_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..817b258000b9f13b5dbbc8f498b00cc74e7dc1e0 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/unlink_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_UNLINK_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_UNLINK_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class UnlinkAni final { +public: + static void UnlinkSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_UNLINK_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/utimes_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/utimes_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..849f10d4d789b07971c92d3f5ac422d073f8642a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/utimes_ani.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 "utimes_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" +#include "utimes_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void UtimesAni::Utimes( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_double mtime) +{ + auto [succPath, newPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + auto ret = UtimesCore::DoUtimes(newPath, static_cast(mtime)); + if (!ret.IsSuccess()) { + HILOGE("Utimes failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/utimes_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/utimes_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..118f7d25ad1cd1fb7cc4442f4e4826af311a36f4 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/utimes_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_UTIMES_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_UTIMES_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class UtimesAni final { +public: + static void Utimes( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_double mtime); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_UTIMES_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/write_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/write_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a87254108e209a06388e25516bac32315abe795e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/write_ani.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025 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 "write_ani.h" + +#include +#include "ani_helper.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" +#include "write_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +static tuple> ToWriteOptions(ani_env *env, ani_object obj) +{ + WriteOptions options; + ani_boolean isUndefined; + env->Reference_IsUndefined(obj, &isUndefined); + if (isUndefined) { + return { true, nullopt }; + } + + auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, "offset"); + if (!succOffset) { + HILOGE("Illegal option.offset parameter"); + return { false, nullopt }; + } + options.offset = offset; + + auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, "length"); + if (!succLength) { + HILOGE("Illegal option.length parameter"); + return { false, nullopt }; + } + options.length = length; + + auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj); + if (!succEncoding) { + HILOGE("Illegal option.encoding parameter"); + return { false, nullopt }; + } + options.encoding = encoding; + return { true, make_optional(move(options)) }; +} + +static std::tuple ParseStringBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + env->FindClass("Lstd/core/String;", &cls); + + ani_boolean isString; + env->Object_InstanceOf(buf, cls, &isString); + if (!isString) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, std::move(result) }; +} + +static std::tuple ParseArrayBuffer(ani_env *env, const ani_object &buf) +{ + ani_class cls; + env->FindClass("Lescompat/ArrayBuffer;", &cls); + + ani_boolean isArrayBuffer; + env->Object_InstanceOf(buf, cls, &isArrayBuffer); + if (!isArrayBuffer) { + return { false, {} }; + } + auto result = static_cast(buf); + return { true, std::move(result) }; +} + +ani_double WriteAni::WriteSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_object buf, ani_object options) +{ + auto [succOp, op] = ToWriteOptions(env, options); + if (!succOp) { + HILOGE("Failed to resolve options!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + + auto [isString, stringBuffer] = ParseStringBuffer(env, buf); + if (isString) { + auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer); + if (!succBuf) { + HILOGE("Failed to resolve stringBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = WriteCore::DoWrite(static_cast(fd), buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); + } + + auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf); + if (isArrayBuffer) { + auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer); + if (!succBuf) { + HILOGE("Failed to resolve arrayBuffer!"); + ErrorHandler::Throw(env, EINVAL); + return -1; + } + auto ret = WriteCore::DoWrite(static_cast(fd), buffer, op); + if (!ret.IsSuccess()) { + HILOGE("write buffer failed!"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return -1; + } + return static_cast(ret.GetData().value()); + } + HILOGE("Unsupported buffer type!"); + ErrorHandler::Throw(env, EINVAL); + return -1; +} +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/write_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/write_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..aeb6e2c4c841a9b2cd5f95958fed92ac0c383c37 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/write_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_WRITE_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_WRITE_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class WriteAni final { +public: + static ani_double WriteSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_double fd, ani_object buf, ani_object options); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_WRITE_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/xattr_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/xattr_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47e6d92a513b2e3ed172026caa532a295519dabe --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/xattr_ani.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025 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 "xattr_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "type_converter.h" +#include "xattr_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +void XattrAni::SetXattrSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string key, ani_string value) +{ + auto [pathSucc, pathStr] = TypeConverter::ToUTF8String(env, path); + if (!pathSucc) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [keySucc, keyStr] = TypeConverter::ToUTF8String(env, key); + if (!keySucc) { + HILOGE("Invalid key"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [valueSucc, valueStr] = TypeConverter::ToUTF8String(env, value); + if (!valueSucc) { + HILOGE("Invalid value"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = XattrCore::DoSetXattr(pathStr, keyStr, valueStr); + if (!ret.IsSuccess()) { + HILOGE("DoSetXattr failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +ani_string XattrAni::GetXattrSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string key) +{ + auto [pathSucc, pathStr] = TypeConverter::ToUTF8String(env, path); + if (!pathSucc) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [keySucc, keyStr] = TypeConverter::ToUTF8String(env, key); + if (!keySucc) { + HILOGE("Invalid key"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = XattrCore::DoGetXattr(pathStr, keyStr); + if (!ret.IsSuccess()) { + HILOGE("DoSetXattr failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const auto &res = ret.GetData().value(); + auto [succ, result] = TypeConverter::ToAniString(env, res); + if (!succ) { + HILOGE("Create ani_string error"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/xattr_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/xattr_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..2bc788d12e55bf19e29f8a2b4ca9a541a4b70e1e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/xattr_ani.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 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_ANI_XATTR_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_XATTR_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class XattrAni final { +public: + static void SetXattrSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string key, ani_string value); + static ani_string GetXattrSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string key); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_XATTR_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/close_core.cpp b/interfaces/kits/js/src/mod_fs/properties/close_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ac7a784072edf1cec1c148bf8f5c2319064bd50 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/close_core.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 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 "close_core.h" + +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static int32_t CloseFd(int fd) +{ + std::unique_ptr close_req = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!close_req) { + HILOGE("Failed to request heap memory."); + return 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 ret; + } + return ERRNO_NOERR; +} + +static bool ValidFd(const int32_t &fd) +{ + if (fd < 0) { + HILOGE("Invalid fd"); + return false; + } + return true; +} + +FsResult CloseCore::DoClose(const int32_t &fd) +{ + if (!ValidFd(fd)) { + return FsResult::Error(EINVAL); + } + auto err = CloseFd(fd); + if (err) { + return FsResult::Error(err); + } + return FsResult::Success(); +} +} // namespace OHOS::FileManagement::ModuleFileIO diff --git a/interfaces/kits/js/src/mod_fs/properties/close_core.h b/interfaces/kits/js/src/mod_fs/properties/close_core.h new file mode 100644 index 0000000000000000000000000000000000000000..1bbdd1c3194b641e5d26a5f02ca94f479aeaeab8 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/close_core.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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_CLOSE_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CLOSE_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" +#include "fs_result.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +class CloseCore final { +public: + static FsResult DoClose(const int32_t &fd); +}; + +const std::string PROCEDURE_CLOSE_NAME = "FileIOClose"; +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CLOSE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/copy_core.cpp b/interfaces/kits/js/src/mod_fs/properties/copy_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8378f897d6a83ad0bf08dc09f6ac53fdff87c8c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/copy_core.cpp @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2023-2024 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 "copy_core.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "datashare_helper.h" +#include "file_uri.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "ipc_skeleton.h" +#include "system_ability_definition.h" +#include "trans_listener_core.h" +#include "utils_log.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace AppFileService::ModuleFileUri; +namespace fs = std::filesystem; +const std::string FILE_PREFIX_NAME = "file://"; +const std::string NETWORK_PARA = "?networkid="; +const string PROCEDURE_COPY_NAME = "FileFSCopy"; +const std::string MEDIALIBRARY_DATA_URI = "datashare:///media"; +const std::string MEDIA = "media"; +const int SLEEP_TIME = 100000; +constexpr int DISMATCH = 0; +constexpr int MATCH = 1; +constexpr int BUF_SIZE = 1024; +constexpr size_t MAX_SIZE = 1024 * 1024 * 4; +constexpr std::chrono::milliseconds NOTIFY_PROGRESS_DELAY(300); +std::recursive_mutex CopyCore::mutex_; +std::map> CopyCore::jsCbMap_; + +static string GetModeFromFlags(unsigned int flags) +{ + const string readMode = "r"; + const string writeMode = "w"; + const string appendMode = "a"; + const string truncMode = "t"; + string mode = readMode; + mode += (((flags & O_RDWR) == O_RDWR) ? writeMode : ""); + mode = (((flags & O_WRONLY) == O_WRONLY) ? writeMode : mode); + if (mode != readMode) { + mode += ((flags & O_TRUNC) ? truncMode : ""); + mode += ((flags & O_APPEND) ? appendMode : ""); + } + return mode; +} + +static int OpenSrcFile(const string &srcPth, std::shared_ptr infos, int32_t &srcFd) +{ + Uri uri(infos->srcUri); + if (uri.GetAuthority() == MEDIA) { + std::shared_ptr dataShareHelper = nullptr; + sptr remote = new (std::nothrow) IRemoteStub(); + if (!remote) { + HILOGE("Failed to get remote object"); + return ENOMEM; + } + dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI); + if (!dataShareHelper) { + HILOGE("Failed to connect to datashare"); + return E_PERMISSION; + } + srcFd = dataShareHelper->OpenFile(uri, GetModeFromFlags(O_RDONLY)); + if (srcFd < 0) { + HILOGE("Open media uri by data share fail. ret = %{public}d", srcFd); + return EPERM; + } + } else { + srcFd = open(srcPth.c_str(), O_RDONLY); + if (srcFd < 0) { + HILOGE("Error opening src file descriptor. errno = %{public}d", errno); + return errno; + } + } + return ERRNO_NOERR; +} + +static int SendFileCore(std::unique_ptr srcFdg, + std::unique_ptr destFdg, + std::shared_ptr infos) +{ + std::unique_ptr sendFileReq = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (sendFileReq == nullptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int64_t offset = 0; + struct stat srcStat{}; + if (fstat(srcFdg->GetFD(), &srcStat) < 0) { + HILOGE("Failed to get stat of file by fd: %{public}d ,errno = %{public}d", srcFdg->GetFD(), errno); + return errno; + } + int32_t ret = 0; + int64_t size = static_cast(srcStat.st_size); + while (size >= 0) { + ret = uv_fs_sendfile(nullptr, sendFileReq.get(), destFdg->GetFD(), srcFdg->GetFD(), + offset, MAX_SIZE, nullptr); + if (ret < 0) { + HILOGE("Failed to sendfile by errno : %{public}d", errno); + return errno; + } + if (infos != nullptr && infos->taskSignal != nullptr) { + if (infos->taskSignal->CheckCancelIfNeed(infos->srcPath)) { + HILOGE("===Copy Task Canceled Success"); + return ECANCELED; + } + } + offset += static_cast(ret); + size -= static_cast(ret); + if (ret == 0) { + break; + } + } + if (size != 0) { + HILOGE("The execution of the sendfile task was terminated, remaining file size %{public}" PRIu64, size); + return EIO; + } + return ERRNO_NOERR; +} + +bool CopyCore::IsValidUri(const std::string &uri) +{ + return uri.find(FILE_PREFIX_NAME) == 0; +} + +bool CopyCore::ValidOperand(std::string uriStr) +{ + if (IsValidUri(uriStr)) { + return true; + } + return false; +} + +bool CopyCore::IsRemoteUri(const std::string &uri) +{ + // NETWORK_PARA + return uri.find(NETWORK_PARA) != uri.npos; +} + +bool CopyCore::IsDirectory(const std::string &path) +{ + struct stat buf {}; + int ret = stat(path.c_str(), &buf); + if (ret == -1) { + HILOGE("stat failed, errno is %{public}d", errno); + return false; + } + return (buf.st_mode & S_IFMT) == S_IFDIR; +} + +bool CopyCore::IsFile(const std::string &path) +{ + struct stat buf {}; + int ret = stat(path.c_str(), &buf); + if (ret == -1) { + HILOGI("stat failed, errno is %{public}d, ", errno); + return false; + } + return (buf.st_mode & S_IFMT) == S_IFREG; +} + +bool CopyCore::IsMediaUri(const std::string &uriPath) +{ + Uri uri(uriPath); + string bundleName = uri.GetAuthority(); + return bundleName == MEDIA; +} + +tuple CopyCore::GetFileSize(const std::string &path) +{ + struct stat buf {}; + int ret = stat(path.c_str(), &buf); + if (ret == -1) { + HILOGI("Stat failed."); + return { errno, 0 }; + } + return { ERRNO_NOERR, buf.st_size }; +} + +int CopyCore::CheckOrCreatePath(const std::string &destPath) +{ + std::error_code errCode; + if (!filesystem::exists(destPath, errCode) && errCode.value() == ERRNO_NOERR) { + HILOGI("destPath not exist"); + auto file = open(destPath.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (file < 0) { + HILOGE("Error opening file descriptor. errno = %{public}d", errno); + return errno; + } + close(file); + } else if (errCode.value() != 0) { + return errCode.value(); + } + return ERRNO_NOERR; +} + +int CopyCore::CopyFile(const string &src, const string &dest, std::shared_ptr infos) +{ + HILOGD("src = %{public}s, dest = %{public}s", GetAnonyString(src).c_str(), GetAnonyString(dest).c_str()); + int32_t srcFd = -1; + int32_t ret = OpenSrcFile(src, infos, srcFd); + if (srcFd < 0) { + return ret; + } + auto destFd = open(dest.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (destFd < 0) { + HILOGE("Error opening dest file descriptor. errno = %{public}d", errno); + close(srcFd); + return errno; + } + auto srcFdg = CreateUniquePtr(srcFd, true); + auto destFdg = CreateUniquePtr(destFd, true); + if (srcFdg == nullptr || destFdg == nullptr) { + HILOGE("Failed to request heap memory."); + close(srcFd); + close(destFd); + return ENOMEM; + } + return SendFileCore(move(srcFdg), move(destFdg), infos); +} + +int CopyCore::MakeDir(const string &path) +{ + filesystem::path destDir(path); + std::error_code errCode; + if (!filesystem::create_directory(destDir, errCode)) { + HILOGE("Failed to create directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +int CopyCore::CopySubDir(const string &srcPath, const string &destPath, std::shared_ptr infos) +{ + std::error_code errCode; + if (!filesystem::exists(destPath, errCode) && errCode.value() == ERRNO_NOERR) { + int res = MakeDir(destPath); + if (res != ERRNO_NOERR) { + HILOGE("Failed to mkdir"); + return res; + } + } else if (errCode.value() != ERRNO_NOERR) { + HILOGE("fs exists fail, errcode is %{public}d", errCode.value()); + return errCode.value(); + } + uint32_t watchEvents = IN_MODIFY; + if (infos->notifyFd >= 0) { + int newWd = inotify_add_watch(infos->notifyFd, destPath.c_str(), watchEvents); + if (newWd < 0) { + HILOGE("inotify_add_watch, newWd is unvaild, newWd = %{public}d", newWd); + return errno; + } + { + std::lock_guard lock(CopyCore::mutex_); + auto iter = CopyCore::jsCbMap_.find(*infos); + auto receiveInfo = CreateSharedPtr(); + if (receiveInfo == nullptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + receiveInfo->path = destPath; + if (iter == CopyCore::jsCbMap_.end() || iter->second == nullptr) { + HILOGE("Failed to find infos, srcPath = %{public}s, destPath = %{public}s", + GetAnonyString(infos->srcPath).c_str(), GetAnonyString(infos->destPath).c_str()); + return UNKNOWN_ERR; + } + iter->second->wds.push_back({ newWd, receiveInfo }); + } + } + return RecurCopyDir(srcPath, destPath, infos); +} + +static int FilterFunc(const struct dirent *filename) +{ + if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") { + return DISMATCH; + } + return MATCH; +} + +struct NameList { + struct dirent **namelist = { nullptr }; + int direntNum = 0; +}; + +static void Deleter(struct NameList *arg) +{ + for (int i = 0; i < arg->direntNum; i++) { + free((arg->namelist)[i]); + (arg->namelist)[i] = nullptr; + } + free(arg->namelist); + arg->namelist = nullptr; + delete arg; + arg = nullptr; +} + +std::string CopyCore::GetRealPath(const std::string& path) +{ + fs::path tempPath(path); + fs::path realPath{}; + for (const auto& component : tempPath) { + if (component == ".") { + continue; + } else if (component == "..") { + realPath = realPath.parent_path(); + } else { + realPath /= component; + } + } + return realPath.string(); +} + +uint64_t CopyCore::GetDirSize(std::shared_ptr infos, std::string path) +{ + unique_ptr pNameList = { new (nothrow) struct NameList, Deleter }; + if (pNameList == nullptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort); + pNameList->direntNum = num; + + long int size = 0; + for (int i = 0; i < num; i++) { + string dest = path + '/' + string((pNameList->namelist[i])->d_name); + if ((pNameList->namelist[i])->d_type == DT_LNK) { + continue; + } + if ((pNameList->namelist[i])->d_type == DT_DIR) { + size += static_cast(GetDirSize(infos, dest)); + } else { + struct stat st {}; + if (stat(dest.c_str(), &st) == -1) { + return size; + } + size += st.st_size; + } + } + return size; +} + +int CopyCore::RecurCopyDir(const string &srcPath, const string &destPath, std::shared_ptr infos) +{ + unique_ptr pNameList = { new (nothrow) struct NameList, Deleter }; + if (pNameList == nullptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(srcPath.c_str(), &(pNameList->namelist), FilterFunc, alphasort); + pNameList->direntNum = num; + + for (int i = 0; i < num; i++) { + string src = srcPath + '/' + string((pNameList->namelist[i])->d_name); + string dest = destPath + '/' + string((pNameList->namelist[i])->d_name); + if ((pNameList->namelist[i])->d_type == DT_LNK) { + continue; + } + int ret = ERRNO_NOERR; + if ((pNameList->namelist[i])->d_type == DT_DIR) { + ret = CopySubDir(src, dest, infos); + } else { + infos->filePaths.insert(dest); + ret = CopyFile(src, dest, infos); + } + if (ret != ERRNO_NOERR) { + return ret; + } + } + return ERRNO_NOERR; +} + +int CopyCore::CopyDirFunc(const string &src, const string &dest, std::shared_ptr infos) +{ + HILOGD("CopyDirFunc in, src = %{public}s, dest = %{public}s", GetAnonyString(src).c_str(), + GetAnonyString(dest).c_str()); + size_t found = dest.find(src); + if (found != std::string::npos && found == 0) { + return EINVAL; + } + fs::path srcPath = fs::u8path(src); + std::string dirName; + if (srcPath.has_parent_path()) { + dirName = srcPath.parent_path().filename(); + } + string destStr = dest + "/" + dirName; + return CopySubDir(src, destStr, infos); +} + +int CopyCore::ExecLocal(std::shared_ptr infos, std::shared_ptr callback) +{ + if (infos->isFile) { + if (infos->srcPath == infos->destPath) { + HILOGE("The src and dest is same"); + return EINVAL; + } + int ret = CheckOrCreatePath(infos->destPath); + if (ret != ERRNO_NOERR) { + HILOGE("check or create fail, error code is %{public}d", ret); + return ret; + } + } + if (!infos->hasListener) { + return ExecCopy(infos); + } + auto ret = SubscribeLocalListener(infos, callback); + if (ret != ERRNO_NOERR) { + HILOGE("Failed to subscribe local listener, errno = %{public}d", ret); + return ret; + } + StartNotify(infos, callback); + return ExecCopy(infos); +} + +int CopyCore::SubscribeLocalListener(std::shared_ptr infos, + std::shared_ptr callback) +{ + infos->notifyFd = inotify_init(); + if (infos->notifyFd < 0) { + HILOGE("Failed to init inotify, errno:%{public}d", errno); + return errno; + } + infos->eventFd = eventfd(0, EFD_CLOEXEC); + if (infos->eventFd < 0) { + HILOGE("Failed to init eventFd, errno:%{public}d", errno); + return errno; + } + callback->notifyFd = infos->notifyFd; + callback->eventFd = infos->eventFd; + int newWd = inotify_add_watch(infos->notifyFd, infos->destPath.c_str(), IN_MODIFY); + if (newWd < 0) { + auto errCode = errno; + HILOGE("Failed to add watch, errno = %{public}d, notifyFd: %{public}d, destPath: %{public}s", errno, + infos->notifyFd, infos->destPath.c_str()); + CloseNotifyFdLocked(infos, callback); + return errCode; + } + auto receiveInfo = CreateSharedPtr(); + if (receiveInfo == nullptr) { + HILOGE("Failed to request heap memory."); + inotify_rm_watch(infos->notifyFd, newWd); + CloseNotifyFdLocked(infos, callback); + return ENOMEM; + } + receiveInfo->path = infos->destPath; + callback->wds.push_back({ newWd, receiveInfo }); + if (!infos->isFile) { + callback->totalSize = GetDirSize(infos, infos->srcPath); + return ERRNO_NOERR; + } + auto [err, fileSize] = GetFileSize(infos->srcPath); + if (err == ERRNO_NOERR) { + callback->totalSize = fileSize; + } + return err; +} + +std::shared_ptr CopyCore::RegisterListener(const std::shared_ptr &infos) +{ + auto callback = CreateSharedPtr(infos->listenerCb); + if (callback == nullptr) { + HILOGE("Failed to request heap memory."); + return nullptr; + } + std::lock_guard lock(mutex_); + auto iter = jsCbMap_.find(*infos); + if (iter != jsCbMap_.end()) { + HILOGE("CopyCore::RegisterListener, already registered."); + return nullptr; + } + jsCbMap_.insert({ *infos, callback }); + return callback; +} + +void CopyCore::UnregisterListener(std::shared_ptr fileInfos) +{ + if (fileInfos == nullptr) { + HILOGE("fileInfos is nullptr"); + return; + } + std::lock_guard lock(mutex_); + auto iter = jsCbMap_.find(*fileInfos); + if (iter == jsCbMap_.end()) { + HILOGI("It is not be registered."); + return; + } + jsCbMap_.erase(*fileInfos); +} + +void CopyCore::ReceiveComplete(UvEntryCore *entry) +{ + if (entry == nullptr) { + HILOGE("entry pointer is nullptr."); + return; + } + auto processedSize = entry->progressSize; + if (processedSize < entry->callback->maxProgressSize) { + HILOGE("enter ReceiveComplete2"); + return; + } + entry->callback->maxProgressSize = processedSize; + + entry->callback->listenerCb(processedSize, entry->totalSize); +} + +UvEntryCore *CopyCore::GetUVEntry(std::shared_ptr infos) +{ + UvEntryCore *entry = nullptr; + { + std::lock_guard lock(mutex_); + auto iter = jsCbMap_.find(*infos); + if (iter == jsCbMap_.end()) { + HILOGE("Failed to find callback"); + return nullptr; + } + auto callback = iter->second; + entry = new (std::nothrow) UvEntryCore(iter->second, infos); + if (entry == nullptr) { + HILOGE("entry ptr is nullptr."); + return nullptr; + } + entry->progressSize = callback->progressSize; + entry->totalSize = callback->totalSize; + } + return entry; +} + +void CopyCore::OnFileReceive(std::shared_ptr infos) +{ + UvEntryCore *entry = GetUVEntry(infos); + if (entry == nullptr) { + HILOGE("failed to get uv entry"); + return; + } + ReceiveComplete(entry); +} + +std::shared_ptr CopyCore::GetReceivedInfo(int wd, std::shared_ptr callback) +{ + auto it = find_if(callback->wds.begin(), callback->wds.end(), [wd](const auto& item) { + return item.first == wd; + }); + if (it != callback->wds.end()) { + return it->second; + } + return nullptr; +} + +bool CopyCore::CheckFileValid(const std::string &filePath, std::shared_ptr infos) +{ + return infos->filePaths.count(filePath) != 0; +} + +int CopyCore::UpdateProgressSize(const std::string &filePath, + std::shared_ptr receivedInfo, + std::shared_ptr callback) +{ + auto [err, fileSize] = GetFileSize(filePath); + if (err != ERRNO_NOERR) { + HILOGE("GetFileSize failed, err: %{public}d.", err); + return err; + } + auto size = fileSize; + auto iter = receivedInfo->fileList.find(filePath); + if (iter == receivedInfo->fileList.end()) { + receivedInfo->fileList.insert({ filePath, size }); + callback->progressSize += size; + } else { // file + if (size > iter->second) { + callback->progressSize += (size - iter->second); + iter->second = size; + } + } + return ERRNO_NOERR; +} + +std::shared_ptr CopyCore::GetRegisteredListener(std::shared_ptr infos) +{ + std::lock_guard lock(mutex_); + auto iter = jsCbMap_.find(*infos); + if (iter == jsCbMap_.end()) { + HILOGE("It is not registered."); + return nullptr; + } + return iter->second; +} + +void CopyCore::CloseNotifyFd(std::shared_ptr infos, std::shared_ptr callback) +{ + callback->closed = false; + infos->eventFd = -1; + infos->notifyFd = -1; + { + std::unique_lock lock(callback->cvLock); + callback->CloseFd(); + callback->cv.notify_one(); + } +} + +void CopyCore::CloseNotifyFdLocked(std::shared_ptr infos, std::shared_ptr callback) +{ + { + lock_guard lock(callback->readMutex); + callback->closed = true; + if (callback->reading) { + HILOGE("close while reading"); + return; + } + } + CloseNotifyFd(infos, callback); +} + +tuple CopyCore::HandleProgress( + inotify_event *event, std::shared_ptr infos, std::shared_ptr callback) +{ + if (callback == nullptr) { + return { true, EINVAL, false }; + } + auto receivedInfo = GetReceivedInfo(event->wd, callback); + if (receivedInfo == nullptr) { + return { true, EINVAL, false }; + } + std::string fileName = receivedInfo->path; + if (!infos->isFile) { // files under subdir + fileName += "/" + string(event->name); + if (!CheckFileValid(fileName, infos)) { + return { true, EINVAL, false }; + } + auto err = UpdateProgressSize(fileName, receivedInfo, callback); + if (err != ERRNO_NOERR) { + return { false, err, false }; + } + } else { + auto [err, fileSize] = GetFileSize(fileName); + if (err != ERRNO_NOERR) { + return { false, err, false }; + } + callback->progressSize = fileSize; + } + return { true, callback->errorCode, true }; +} + +void CopyCore::ReadNotifyEvent(std::shared_ptr infos) +{ + char buf[BUF_SIZE] = { 0 }; + struct inotify_event *event = nullptr; + int len = 0; + int64_t index = 0; + auto callback = GetRegisteredListener(infos); + while (((len = read(infos->notifyFd, &buf, sizeof(buf))) < 0) && (errno == EINTR)) {} + while (infos->run && index < len) { + event = reinterpret_cast(buf + index); + auto [needContinue, errCode, needSend] = HandleProgress(event, infos, callback); + if (!needContinue) { + infos->exceptionCode = errCode; + return; + } + if (needContinue && !needSend) { + index += static_cast(sizeof(struct inotify_event) + event->len); + continue; + } + if (callback->progressSize == callback->totalSize) { + infos->run = false; + return; + } + auto currentTime = std::chrono::steady_clock::now(); + if (currentTime >= infos->notifyTime) { + OnFileReceive(infos); + infos->notifyTime = currentTime + NOTIFY_PROGRESS_DELAY; + } + index += static_cast(sizeof(struct inotify_event) + event->len); + } +} + +void CopyCore::ReadNotifyEventLocked(std::shared_ptr infos, std::shared_ptr callback) +{ + { + std::lock_guard lock(callback->readMutex); + if (callback->closed) { + HILOGE("read after close"); + return; + } + callback->reading = true; + } + ReadNotifyEvent(infos); + { + std::lock_guard lock(callback->readMutex); + callback->reading = false; + if (callback->closed) { + HILOGE("close after read"); + CloseNotifyFd(infos, callback); + return; + } + } +} + +void CopyCore::GetNotifyEvent(std::shared_ptr infos) +{ + auto callback = GetRegisteredListener(infos); + if (callback == nullptr) { + infos->exceptionCode = EINVAL; + return; + } + prctl(PR_SET_NAME, "NotifyThread"); + nfds_t nfds = 2; + struct pollfd fds[2]; + fds[0].events = 0; + fds[1].events = POLLIN; + fds[0].fd = infos->eventFd; + fds[1].fd = infos->notifyFd; + while (infos->run && infos->exceptionCode == ERRNO_NOERR && infos->eventFd != -1 && infos->notifyFd != -1) { + auto ret = poll(fds, nfds, -1); + if (ret > 0) { + if (static_cast(fds[0].revents) & POLLNVAL) { + infos->run = false; + return; + } + if (static_cast(fds[1].revents) & POLLIN) { + ReadNotifyEventLocked(infos, callback); + } + } else if (ret < 0 && errno == EINTR) { + continue; + } else { + infos->exceptionCode = errno; + return; + } + { + std::unique_lock lock(callback->cvLock); + callback->cv.wait_for(lock, std::chrono::microseconds(SLEEP_TIME), [callback]() -> bool { + return callback->notifyFd == -1; + }); + } + } +} + +tuple> CopyCore::CreateFileInfos( + const std::string &srcUri, const std::string &destUri, std::optional options) +{ + auto infos = CreateSharedPtr(); + if (infos == nullptr) { + HILOGE("Failed to request heap memory."); + return { ENOMEM, nullptr }; + } + infos->srcUri = srcUri; + infos->destUri = destUri; + FileUri srcFileUri(infos->srcUri); + infos->srcPath = srcFileUri.GetRealPath(); + FileUri dstFileUri(infos->destUri); + infos->destPath = dstFileUri.GetPath(); + infos->srcPath = GetRealPath(infos->srcPath); + infos->destPath = GetRealPath(infos->destPath); + infos->isFile = IsMediaUri(infos->srcUri) || IsFile(infos->srcPath); + infos->notifyTime = std::chrono::steady_clock::now() + NOTIFY_PROGRESS_DELAY; + if (options != std::nullopt) { + if (options.value().listenerCb) { + infos->hasListener = true; + infos->listenerCb = options.value().listenerCb; + } + if (options.value().taskSignalEntityCore != nullptr) { + infos->taskSignal = options.value().taskSignalEntityCore->taskSignal_; + } + } + + return { ERRNO_NOERR, infos }; +} + +void CopyCore::StartNotify(std::shared_ptr infos, std::shared_ptr callback) +{ + if (infos->hasListener && callback != nullptr) { + callback->notifyHandler = std::thread([infos] { + GetNotifyEvent(infos); + }); + } +} + +int CopyCore::ExecCopy(std::shared_ptr infos) +{ + if (infos->isFile && IsFile(infos->destPath)) { + // copyFile + return CopyFile(infos->srcPath.c_str(), infos->destPath.c_str(), infos); + } + if (!infos->isFile && IsDirectory(infos->destPath)) { + if (infos->srcPath.back() != '/') { + infos->srcPath += '/'; + } + if (infos->destPath.back() != '/') { + infos->destPath += '/'; + } + // copyDir + return CopyDirFunc(infos->srcPath.c_str(), infos->destPath.c_str(), infos); + } + return EINVAL; +} + +int CopyCore::ValidParam(const string& src, const string& dest, + std::optional options, + std::shared_ptr &fileInfos) +{ + auto succSrc = ValidOperand(src); + auto succDest = ValidOperand(dest); + if (!succSrc || !succDest) { + HILOGE("The first/second argument requires uri/uri"); + return E_PARAMS; + } + auto [errCode, infos] = CreateFileInfos(src, dest, options); + if (errCode != ERRNO_NOERR) { + return errCode; + } + fileInfos = infos; + return ERRNO_NOERR; +} + +void CopyCore::WaitNotifyFinished(std::shared_ptr callback) +{ + if (callback != nullptr) { + if (callback->notifyHandler.joinable()) { + callback->notifyHandler.join(); + } + } +} + +void CopyCore::CopyComplete(std::shared_ptr infos, std::shared_ptr callback) +{ + if (callback != nullptr && infos->hasListener) { + callback->progressSize = callback->totalSize; + OnFileReceive(infos); + } +} + +FsResult CopyCore::DoCopy(const string& src, const string& dest, std::optional &options) +{ + std::shared_ptr infos = nullptr; + auto result = ValidParam(src, dest, options, infos); + if (result != ERRNO_NOERR) { + return FsResult::Error(result); + } + + auto callback = RegisterListener(infos); + if (callback == nullptr) { + return FsResult::Error(EINVAL); + } + + if (IsRemoteUri(infos->srcUri)) { + if (infos->taskSignal != nullptr) { + infos->taskSignal->MarkRemoteTask(); + } + auto ret = TransListenerCore::CopyFileFromSoftBus(infos->srcUri, infos->destUri, + infos, std::move(callback)); + if (ret != ERRNO_NOERR) { + return FsResult::Error(ret); + } else { + return FsResult::Success(); + } + } + result = CopyCore::ExecLocal(infos, callback); + CloseNotifyFdLocked(infos, callback); + infos->run = false; + WaitNotifyFinished(callback); + if (result != ERRNO_NOERR) { + infos->exceptionCode = result; + return FsResult::Error(infos->exceptionCode); + } + CopyComplete(infos, callback); + if (infos->exceptionCode != ERRNO_NOERR) { + return FsResult::Error(infos->exceptionCode); + } else { + return FsResult::Success(); + } +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/copy_core.h b/interfaces/kits/js/src/mod_fs/properties/copy_core.h new file mode 100644 index 0000000000000000000000000000000000000000..aa731caf82c30ec4a7a30d825c4081d602f1c88b --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/copy_core.h @@ -0,0 +1,198 @@ +/* + * 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 FILEMANAGEMENT_FILE_API_COPY_CORE_H +#define FILEMANAGEMENT_FILE_API_COPY_CORE_H + +#include +#include +#include +#include +#include + +#include "bundle_mgr_client_impl.h" +#include "filemgmt_libfs.h" +#include "filemgmt_libhilog.h" +#include "task_signal.h" +#include "task_signal_entity_core.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace OHOS::AppExecFwk; +using namespace DistributedFS::ModuleTaskSignal; +const uint64_t MAX_VALUE = 0x7FFFFFFFFFFFFFFF; +typedef std::function ProgressListenerCb; + +struct CopyOptions { + ProgressListenerCb listenerCb; + std::shared_ptr taskSignalEntityCore; +}; + +struct ReceiveInfo { + std::string path; // dir name + std::map fileList; // filename, proceededSize +}; + +struct CallbackObjectCore { + ProgressListenerCb listenerCb; + int32_t notifyFd = -1; + int32_t eventFd = -1; + std::vector>> wds; + uint64_t totalSize = 0; + uint64_t progressSize = 0; + uint64_t maxProgressSize = 0; + int32_t errorCode = 0; + std::thread notifyHandler; + std::mutex readMutex; + std::condition_variable cv; + std::mutex cvLock; + bool reading = false; + bool closed = false; + explicit CallbackObjectCore(ProgressListenerCb cb) : listenerCb(cb) {} + + void CloseFd() + { + if (eventFd != -1) { + close(eventFd); + eventFd = -1; + } + if (notifyFd == -1) { + return; + } + for (auto item : wds) { + inotify_rm_watch(notifyFd, item.first); + } + close(notifyFd); + notifyFd = -1; + } + + ~CallbackObjectCore() + { + CloseFd(); + } +}; + +struct FileInfosCore { + std::string srcUri; + std::string destUri; + std::string srcPath; + std::string destPath; + bool isFile = false; + std::chrono::steady_clock::time_point notifyTime; + int32_t notifyFd = -1; + int32_t eventFd = -1; + bool run = true; + bool hasListener = false; + ProgressListenerCb listenerCb; + std::shared_ptr taskSignal = nullptr; + std::set filePaths; + int exceptionCode = ERRNO_NOERR; // notify copy thread or listener thread has exceptions. + bool operator==(const FileInfosCore &infos) const + { + return (srcUri == infos.srcUri && destUri == infos.destUri); + } + bool operator<(const FileInfosCore &infos) const + { + if (srcUri == infos.srcUri) { + return destUri < infos.destUri; + } + return srcUri < infos.srcUri; + } +}; + +struct UvEntryCore { + std::shared_ptr callback; + std::shared_ptr fileInfos; + uint64_t progressSize = 0; + uint64_t totalSize = 0; + UvEntryCore(const std::shared_ptr &cb, std::shared_ptr fileInfos) + : callback(cb), fileInfos(fileInfos) + { + } + explicit UvEntryCore(const std::shared_ptr &cb) : callback(cb) {} +}; + +class CopyCore final { +public: + static std::map> jsCbMap_; + static void UnregisterListener(std::shared_ptr fileInfos); + static std::recursive_mutex mutex_; + static FsResult DoCopy(const string& src, const string& dest, std::optional &options); + +private: + // operator of napi + static bool ValidOperand(std::string uriStr); + static int CheckOrCreatePath(const std::string &destPath); + static int ValidParam(const string& src, const string& dest, std::optional options, + std::shared_ptr &fileInfos); + + // operator of local listener + static int ExecLocal(std::shared_ptr infos, std::shared_ptr callback); + static void CopyComplete(std::shared_ptr infos, std::shared_ptr callback); + static void WaitNotifyFinished(std::shared_ptr callback); + static void ReadNotifyEvent(std::shared_ptr infos); + static void ReadNotifyEventLocked(std::shared_ptr infos, + std::shared_ptr callback); + static int SubscribeLocalListener(std::shared_ptr infos, + std::shared_ptr callback); + static std::shared_ptr RegisterListener( + const std::shared_ptr &infos); + static void OnFileReceive(std::shared_ptr infos); + static void GetNotifyEvent(std::shared_ptr infos); + static void StartNotify(std::shared_ptr infos, std::shared_ptr callback); + static UvEntryCore *GetUVEntry(std::shared_ptr infos); + static void ReceiveComplete(UvEntryCore *entry); + static std::shared_ptr GetRegisteredListener(std::shared_ptr infos); + static void CloseNotifyFd(std::shared_ptr infos, std::shared_ptr callback); + static void CloseNotifyFdLocked(std::shared_ptr infos, + std::shared_ptr callback); + + // operator of file + static int RecurCopyDir(const string &srcPath, const string &destPath, std::shared_ptr infos); + static tuple GetFileSize(const std::string &path); + static uint64_t GetDirSize(std::shared_ptr infos, std::string path); + static int CopyFile(const string &src, const string &dest, std::shared_ptr infos); + static int MakeDir(const string &path); + static int CopySubDir(const string &srcPath, const string &destPath, std::shared_ptr infos); + static int CopyDirFunc(const string &src, const string &dest, std::shared_ptr infos); + static tuple> CreateFileInfos( + const std::string &srcUri, const std::string &destUri, std::optional options); + static int ExecCopy(std::shared_ptr infos); + + // operator of file size + static int UpdateProgressSize(const std::string &filePath, + std::shared_ptr receivedInfo, + std::shared_ptr callback); + static tuple HandleProgress( + inotify_event *event, std::shared_ptr infos, std::shared_ptr callback); + static std::shared_ptr GetReceivedInfo(int wd, std::shared_ptr callback); + static bool CheckFileValid(const std::string &filePath, std::shared_ptr infos); + + // operator of uri or path + static bool IsValidUri(const std::string &uri); + static bool IsRemoteUri(const std::string &uri); + static bool IsDirectory(const std::string &path); + static bool IsFile(const std::string &path); + static bool IsMediaUri(const std::string &uriPath); + static std::string ConvertUriToPath(const std::string &uri); + static std::string GetRealPath(const std::string& path); +}; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // FILEMANAGEMENT_FILE_API_COPY_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/copy_file_core.cpp b/interfaces/kits/js/src/mod_fs/properties/copy_file_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3dc5325075d72b851592466403a027961da6c320 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/copy_file_core.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2025 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 "copy_file_core.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static int32_t IsAllPath(FileInfo &srcFile, FileInfo &destFile) +{ +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + filesystem::path srcPath(string(srcFile.path.get())); + filesystem::path dstPath(string(destFile.path.get())); + error_code errCode; + if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, + errCode)) { + HILOGE("Failed to copy file, error code: %{public}d", errCode.value()); + return errCode.value(); + } +#else + std::unique_ptr copyfile_req = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup}; + if (!copyfile_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_copyfile(nullptr, copyfile_req.get(), srcFile.path.get(), destFile.path.get(), + UV_FS_COPYFILE_FICLONE, nullptr); + if (ret < 0) { + HILOGE("Failed to copy file when all parameters are paths"); + return ret; + } +#endif + return ERRNO_NOERR; +} + +static int32_t SendFileCore(FileInfo &srcFdg, FileInfo &destFdg, struct stat &statbf) +{ + std::unique_ptr sendfile_req = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup}; + if (!sendfile_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int64_t offset = 0; + size_t size = static_cast(statbf.st_size); + int ret = 0; + while (size > 0) { + ret = uv_fs_sendfile(nullptr, sendfile_req.get(), destFdg.fdg->GetFD(), srcFdg.fdg->GetFD(), + offset, std::min(MAX_SIZE, size), nullptr); + if (ret < 0) { + HILOGE("Failed to sendfile by ret : %{public}d", ret); + return ret; + } + if (static_cast(ret) > size) { + HILOGE("More bytes returned than the size of the file. The file size is " + "%{public}zu" + "The bytes returned is %{public}d", + size, ret); + return EIO; + } + offset += static_cast(ret); + size -= static_cast(ret); + if (ret == 0) { + break; + } + } + if (size != 0) { + HILOGE("The execution of the sendfile task was terminated, remaining file " + "size %{public}zu", size); + return EIO; + } + return ERRNO_NOERR; +} + +static int32_t TruncateCore(const FileInfo &fileInfo) +{ + std::unique_ptr ftruncateReq = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup}; + if (!ftruncateReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_ftruncate(nullptr, ftruncateReq.get(), fileInfo.fdg->GetFD(), 0, nullptr); + if (ret < 0) { + HILOGE("Failed to truncate dstFile with ret: %{public}d", ret); + return ret; + } + return ERRNO_NOERR; +} + +static int32_t OpenCore(FileInfo &fileInfo, const int flags, const int mode) +{ + std::unique_ptr openReq = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup}; + if (!openReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_open(nullptr, openReq.get(), fileInfo.path.get(), flags, mode, nullptr); + if (ret < 0) { + HILOGE("Failed to open srcFile with ret: %{public}d", ret); + return ret; + } + fileInfo.fdg = CreateUniquePtr(ret, true); + if (fileInfo.fdg == nullptr) { + HILOGE("Failed to request heap memory."); + close(ret); + return ENOMEM; + } + return ERRNO_NOERR; +} + +static int32_t OpenFile(FileInfo &srcFile, FileInfo &destFile) +{ + if (srcFile.isPath) { + auto openResult = OpenCore(srcFile, UV_FS_O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (openResult) { + return openResult; + } + } + struct stat statbf; + if (fstat(srcFile.fdg->GetFD(), &statbf) < 0) { + HILOGE("Failed to get stat of file by fd: %{public}d", srcFile.fdg->GetFD()); + return errno; + } + if (destFile.isPath) { + auto openResult = OpenCore(destFile, UV_FS_O_RDWR | UV_FS_O_CREAT | UV_FS_O_TRUNC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); + if (openResult) { + return openResult; + } + } else { + auto truncateResult = TruncateCore(destFile); + if (truncateResult) { + return truncateResult; + } + auto ret = lseek(destFile.fdg->GetFD(), 0, SEEK_SET); + if (ret < 0) { + HILOGE("Failed to lseek destFile, errno: %{public}d", errno); + return errno; + } + } + if (statbf.st_size == 0) { + return ERRNO_NOERR; + } + return SendFileCore(srcFile, destFile, statbf); +} + +static tuple ValidMode(const optional &mode) +{ + int modeValue = 0; + if (mode.has_value()) { + modeValue = mode.value(); + if (modeValue) { + return { false, modeValue }; + } + } + return { true, modeValue }; +} + +FsResult CopyFileCore::DoCopyFile(FileInfo &src, FileInfo &dest, + const optional &mode) +{ + auto [succMode, modeValue] = ValidMode(mode); + if (!succMode) { + HILOGE("Failed to convert mode to int32"); + return FsResult::Error(EINVAL); + } + + if (src.isPath && dest.isPath) { + auto err = IsAllPath(src, dest); + if (err) { + return FsResult::Error(err); + } + } else { + auto err = OpenFile(src, dest); + if (err) { + return FsResult::Error(err); + } + } + return FsResult::Success(); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/copy_file_core.h b/interfaces/kits/js/src/mod_fs/properties/copy_file_core.h new file mode 100644 index 0000000000000000000000000000000000000000..464604c65c1c56fb5d5c4353432392c46e1fa62a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/copy_file_core.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_COPY_FILE_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_COPY_FILE_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +class CopyFileCore final { +public: + static FsResult DoCopyFile(FileInfo &src, FileInfo &dest, + const optional &mode = nullopt); +}; + +constexpr size_t MAX_SIZE = 0x7ffff000; +const string PROCEDURE_COPYFILE_NAME = "FileIOCopyFile"; +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_COPY_FILE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/copy_listener/trans_listener_core.cpp b/interfaces/kits/js/src/mod_fs/properties/copy_listener/trans_listener_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0a27d1de2a76994933670a03c857962491746d67 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/copy_listener/trans_listener_core.cpp @@ -0,0 +1,314 @@ +/* + * 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 "trans_listener_core.h" + +#include +#include +#include + +#include "ipc_skeleton.h" +#include "sandbox_helper.h" +#include "uri.h" +#include "dfs_event_dfx.h" +#include "utils_log.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace OHOS::AppFileService; +using namespace AppFileService::ModuleFileUri; +const std::string NETWORK_PARA = "?networkid="; +const std::string FILE_MANAGER_AUTHORITY = "docs"; +const std::string MEDIA_AUTHORITY = "media"; +const std::string DISTRIBUTED_PATH = "/data/storage/el2/distributedfiles/"; +std::atomic TransListenerCore::getSequenceId_ = 0; + +void TransListenerCore::RmDir(const std::string &path) +{ + HILOGI("RmDirm path : %{public}s", GetAnonyString(path).c_str()); + std::filesystem::path pathName(path); + std::error_code errCode; + if (std::filesystem::exists(pathName, errCode)) { + std::filesystem::remove_all(pathName, errCode); + if (errCode.value() != 0) { + HILOGE("Failed to remove directory, error code: %{public}d", errCode.value()); + } + } else { + HILOGE("pathName is not exists, error code: %{public}d", errCode.value()); + } +} + +std::string TransListenerCore::CreateDfsCopyPath() +{ + std::random_device rd; + std::string random = std::to_string(rd()); + while (std::filesystem::exists(DISTRIBUTED_PATH + random)) { + random = std::to_string(rd()); + } + return random; +} + +int TransListenerCore::HandleCopyFailure(CopyEvent ©Event, const Storage::DistributedFile::HmdfsInfo &info, + const std::string &disSandboxPath, const std::string ¤tId) +{ + if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) { + RmDir(disSandboxPath); + } + auto it = softbusErr2ErrCodeTable.find(copyEvent.errorCode); + if (it == softbusErr2ErrCodeTable.end()) { + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE, + RadarReporter::SEND_FILE_ERROR, RadarReporter::CONCURRENT_ID, currentId, + RadarReporter::PACKAGE_NAME, to_string(copyEvent.errorCode)); + return EIO; + } + if (copyEvent.errorCode != DFS_CANCEL_SUCCESS) { + HILOGE("HandleCopyFailure failed, copyEvent.errorCode = %{public}d.", copyEvent.errorCode); + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE, + RadarReporter::SEND_FILE_ERROR, RadarReporter::CONCURRENT_ID, currentId, + RadarReporter::PACKAGE_NAME, to_string(copyEvent.errorCode)); + } + return it->second; +} + +int TransListenerCore::WaitForCopyResult(TransListenerCore* transListener) +{ + if (transListener == nullptr) { + HILOGE("transListener is nullptr"); + return FAILED; + } + std::unique_lock lock(transListener->cvMutex_); + transListener->cv_.wait(lock, [&transListener]() { + return transListener->copyEvent_.copyResult == SUCCESS || + transListener->copyEvent_.copyResult == FAILED; + }); + return transListener->copyEvent_.copyResult; +} + +int TransListenerCore::CopyFileFromSoftBus(const std::string &srcUri, const std::string &destUri, + std::shared_ptr fileInfos, std::shared_ptr callback) +{ + HILOGI("CopyFileFromSoftBus begin."); + std::string currentId = "CopyFile_" + std::to_string(getpid()) + "_" + std::to_string(getSequenceId_); + ++getSequenceId_; + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_SUCCESS, + RadarReporter::BIZ_STATE, RadarReporter::DFX_BEGIN, RadarReporter::PACKAGE_NAME, std::to_string(getpid()), + RadarReporter::CONCURRENT_ID, currentId); + sptr transListener = new (std::nothrow) TransListenerCore(); + if (transListener == nullptr) { + HILOGE("new trans listener failed"); + return ENOMEM; + } + transListener->callback_ = std::move(callback); + + Storage::DistributedFile::HmdfsInfo info{}; + Uri uri(destUri); + info.authority = uri.GetAuthority(); + info.sandboxPath = SandboxHelper::Decode(uri.GetPath()); + std::string disSandboxPath; + auto ret = PrepareCopySession(srcUri, destUri, transListener, info, disSandboxPath); + if (ret != ERRNO_NOERR) { + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE, + RadarReporter::PREPARE_COPY_SESSION_ERROR, RadarReporter::CONCURRENT_ID, currentId, + RadarReporter::PACKAGE_NAME, to_string(ret)); + return EIO; + } + if (fileInfos->taskSignal != nullptr) { + fileInfos->taskSignal->SetFileInfoOfRemoteTask(info.sessionName, fileInfos->srcPath); + } + auto copyResult = WaitForCopyResult(transListener); + if (copyResult == FAILED) { + return HandleCopyFailure(transListener->copyEvent_, info, disSandboxPath, currentId); + } + if (info.authority == FILE_MANAGER_AUTHORITY || info.authority == MEDIA_AUTHORITY) { + HILOGW("Public or media path not copy"); + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_SUCCESS, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::CONCURRENT_ID, currentId); + return ERRNO_NOERR; + } + + ret = CopyToSandBox(srcUri, disSandboxPath, info.sandboxPath, currentId); + RmDir(disSandboxPath); + if (ret != ERRNO_NOERR) { + HILOGE("CopyToSandBox failed, ret = %{public}d.", ret); + return EIO; + } + return ERRNO_NOERR; +} + +int32_t TransListenerCore::PrepareCopySession(const std::string &srcUri, + const std::string &destUri, + TransListenerCore* transListener, + Storage::DistributedFile::HmdfsInfo &info, + std::string &disSandboxPath) +{ + std::string tmpDir; + if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) { + tmpDir = CreateDfsCopyPath(); + disSandboxPath = DISTRIBUTED_PATH + tmpDir; + std::error_code errCode; + if (!std::filesystem::create_directory(disSandboxPath, errCode)) { + HILOGE("Create dir failed, error code: %{public}d", errCode.value()); + return errCode.value(); + } + + auto pos = info.sandboxPath.rfind('/'); + if (pos == std::string::npos) { + HILOGE("invalid file path"); + return EIO; + } + auto sandboxDir = info.sandboxPath.substr(0, pos); + if (std::filesystem::exists(sandboxDir, errCode)) { + info.dirExistFlag = true; + } + } + + info.copyPath = tmpDir; + auto networkId = GetNetworkIdFromUri(srcUri); + HILOGI("dfs PrepareSession begin."); + auto ret = Storage::DistributedFile::DistributedFileDaemonManager::GetInstance().PrepareSession(srcUri, destUri, + networkId, transListener, info); + if (ret != ERRNO_NOERR) { + HILOGE("PrepareSession failed, ret = %{public}d.", ret); + if (info.authority != FILE_MANAGER_AUTHORITY && info.authority != MEDIA_AUTHORITY) { + RmDir(disSandboxPath); + } + return EIO; + } + return ERRNO_NOERR; +} + +int32_t TransListenerCore::CopyToSandBox(const std::string &srcUri, const std::string &disSandboxPath, + const std::string &sandboxPath, const std::string ¤tId) +{ + std::error_code errCode; + if (std::filesystem::exists(sandboxPath) && std::filesystem::is_directory(sandboxPath)) { + HILOGI("Copy dir"); + std::filesystem::copy(disSandboxPath, sandboxPath, + std::filesystem::copy_options::recursive | std::filesystem::copy_options::update_existing, errCode); + if (errCode.value() != 0) { + HILOGE("Copy dir failed: errCode: %{public}d", errCode.value()); + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE, + RadarReporter::COPY_TO_SANDBOX_ERROR, RadarReporter::CONCURRENT_ID, currentId, + RadarReporter::PACKAGE_NAME, to_string(errCode.value())); + return EIO; + } + } else { + HILOGI("Copy file."); + Uri uri(srcUri); + auto fileName = GetFileName(uri.GetPath()); + if (fileName.empty()) { + HILOGE("Get filename failed"); + RmDir(disSandboxPath); + return EIO; + } + std::filesystem::copy(disSandboxPath + fileName, sandboxPath, std::filesystem::copy_options::update_existing, + errCode); + if (errCode.value() != 0) { + HILOGE("Copy file failed: errCode: %{public}d", errCode.value()); + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_FAILED, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::ERROR_CODE, + RadarReporter::COPY_TO_SANDBOX_ERROR, RadarReporter::CONCURRENT_ID, currentId, + RadarReporter::PACKAGE_NAME, to_string(errCode.value())); + return EIO; + } + } + HILOGI("Copy file success."); + RADAR_REPORT(RadarReporter::DFX_SET_DFS, RadarReporter::DFX_SET_BIZ_SCENE, RadarReporter::DFX_SUCCESS, + RadarReporter::BIZ_STATE, RadarReporter::DFX_END, RadarReporter::CONCURRENT_ID, currentId); + return ERRNO_NOERR; +} + +std::string TransListenerCore::GetFileName(const std::string &path) +{ + auto pos = path.find_last_of('/'); + if (pos == std::string::npos) { + HILOGE("invalid path"); + return ""; + } + return SandboxHelper::Decode(path.substr(pos)); +} + +std::string TransListenerCore::GetNetworkIdFromUri(const std::string &uri) +{ + return uri.substr(uri.find(NETWORK_PARA) + NETWORK_PARA.size(), uri.size()); +} + +void TransListenerCore::CallbackComplete(UvEntryCore *entry) +{ + if (entry == nullptr) { + HILOGE("entry pointer is nullptr."); + return; + } + + entry->callback->listenerCb(entry->progressSize, entry->totalSize); +} + +int32_t TransListenerCore::OnFileReceive(uint64_t totalBytes, uint64_t processedBytes) +{ + std::lock_guard lock(callbackMutex_); + if (callback_ == nullptr) { + HILOGE("Failed to parse watcher callback"); + return ENOMEM; + } + + UvEntryCore *entry = new (std::nothrow) UvEntryCore(callback_); + if (entry == nullptr) { + HILOGE("entry ptr is nullptr"); + return ENOMEM; + } + entry->progressSize = processedBytes; + entry->totalSize = totalBytes; + CallbackComplete(entry); + return ERRNO_NOERR; +} + +int32_t TransListenerCore::OnFinished(const std::string &sessionName) +{ + HILOGI("OnFinished"); + { + std::lock_guard lock(callbackMutex_); + callback_ = nullptr; + } + { + std::lock_guard lock(cvMutex_); + copyEvent_.copyResult = SUCCESS; + cv_.notify_all(); + } + return ERRNO_NOERR; +} + +int32_t TransListenerCore::OnFailed(const std::string &sessionName, int32_t errorCode) +{ + HILOGI("OnFailed, errorCode is %{public}d", errorCode); + { + std::lock_guard lock(callbackMutex_); + callback_ = nullptr; + } + { + std::lock_guard lock(cvMutex_); + copyEvent_.copyResult = FAILED; + copyEvent_.errorCode = errorCode; + cv_.notify_all(); + } + return ERRNO_NOERR; +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/copy_listener/trans_listener_core.h b/interfaces/kits/js/src/mod_fs/properties/copy_listener/trans_listener_core.h new file mode 100644 index 0000000000000000000000000000000000000000..97fb954829ba7554b6183632feb555222db41131 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/copy_listener/trans_listener_core.h @@ -0,0 +1,74 @@ +/* + * 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 FILEMANAGEMENT_FILE_API_TRANS_LISTENER_CORE_H +#define FILEMANAGEMENT_FILE_API_TRANS_LISTENER_CORE_H + +#include + +#include "copy_core.h" +#include "distributed_file_daemon_manager.h" +#include "file_trans_listener_stub.h" +#include "file_uri.h" +#include "hmdfs_info.h" +#include "uv.h" + +constexpr int NONE = 0; +constexpr int SUCCESS = 1; +constexpr int FAILED = 2; +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +struct CopyEvent { + int copyResult = NONE; + int32_t errorCode = 0; +}; +class TransListenerCore : public Storage::DistributedFile::FileTransListenerStub { +public: + int32_t OnFileReceive(uint64_t totalBytes, uint64_t processedBytes) override; + int32_t OnFinished(const std::string &sessionName) override; + int32_t OnFailed(const std::string &sessionName, int32_t errorCode) override; + static int CopyFileFromSoftBus(const std::string &srcUri, + const std::string &destUri, + std::shared_ptr fileInfos, + std::shared_ptr callback); +private: + static std::string GetNetworkIdFromUri(const std::string &uri); + static void CallbackComplete(UvEntryCore *entry); + static void RmDir(const std::string &path); + static std::string CreateDfsCopyPath(); + static std::string GetFileName(const std::string &path); + static int32_t CopyToSandBox(const std::string &srcUri, const std::string &disSandboxPath, + const std::string &sandboxPath, const std::string ¤tId); + static int32_t PrepareCopySession(const std::string &srcUri, + const std::string &destUri, + TransListenerCore* transListener, + Storage::DistributedFile::HmdfsInfo &info, + std::string &disSandboxPath); + static int HandleCopyFailure(CopyEvent ©Event, const Storage::DistributedFile::HmdfsInfo &info, + const std::string &disSandboxPath, const std::string ¤tId); + static int WaitForCopyResult(TransListenerCore* transListener); + static std::atomic getSequenceId_; + std::mutex cvMutex_; + std::condition_variable cv_; + CopyEvent copyEvent_; + std::mutex callbackMutex_; + std::shared_ptr callback_; +}; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // FILEMANAGEMENT_FILE_API_TRANS_LISTENER_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile_core.cpp b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3bdc18ce45de2d8bb346db349c45a98f2b2118d0 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile_core.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2025 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_core.h" + +#include + +#include "file_entity.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_randomaccessfile.h" +#include "fs_utils.h" +#include "randomaccessfile_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static tuple ParseStringToFileInfo(const string &path) +{ + if (strlen(path.c_str()) < 0) { + HILOGE("The first argument requires filepath/file"); + return { false, FileInfo { false, nullptr, nullptr }, EINVAL}; + } + OHOS::DistributedFS::FDGuard sfd; + auto fdg = CreateUniquePtr(sfd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + close(sfd); + return { false, FileInfo { false, nullptr, nullptr }, ENOMEM}; + } + size_t length = path.length() + 1; + auto chars = std::make_unique(length); + auto ret = strncpy_s(chars.get(), length, path.c_str(), length - 1); + if (ret != EOK) { + HILOGE("Copy file path failed!"); + return { false, FileInfo { false, nullptr, nullptr }, ENOMEM}; + } + return { true, FileInfo { true, move(chars), move(fdg) }, ERRNO_NOERR}; +} + +static tuple ParseFdToFileInfo(const int32_t &fd) +{ + 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."); + close(dupFd); + return { false, FileInfo { false, nullptr, nullptr }, ENOMEM}; + } + return { true, FileInfo { false, nullptr, move(fdg) }, ERRNO_NOERR}; +} + +static tuple ValidRafOptions(const optional &options) +{ + RandomAccessFileOptions op = options.value(); + int64_t opStart = INVALID_POS; + int64_t opEnd = INVALID_POS; + + optional startOp = op.start; + optional endOp = op.end; + + if (startOp.has_value()) { + int64_t start = 0; + start = startOp.value(); + if (start < 0) { + HILOGE("Invalid option.start, positive integer is desired"); + return {false, opStart, opEnd}; + } + opStart = start; + } + if (endOp.has_value()) { + int64_t end = 0; + end = endOp.value(); + if (end < 0) { + HILOGE("Invalid option.end, positive integer is desired"); + return {false, opStart, opEnd}; + } + opEnd = end; + } + return {true, opStart, opEnd}; +} + +static tuple ValidAndConvertFlags(const optional &mode, + const optional &options, FileInfo &fileInfo) +{ + uint32_t flags = O_RDONLY; + int64_t start = INVALID_POS; + int64_t end = INVALID_POS; + if (fileInfo.isPath && mode.has_value()) { + auto modeValue = mode.value(); + if (modeValue < 0) { + HILOGE("Invalid flags"); + return {false, flags, start, end}; + } + flags = static_cast(modeValue); + (void)FsUtils::ConvertFlags(flags); + } + if (options.has_value()) { + auto [succOpt, start, end] = ValidRafOptions(options); + if (!succOpt) { + HILOGE("invalid RandomAccessFile options"); + return {false, flags, start, end}; + } + } + + return {true, flags, start, end}; +} + +static FsResult InstantiateRandomAccessFile(unique_ptr fdg, + int64_t fp, + int64_t start = INVALID_POS, + int64_t end = INVALID_POS) +{ + FsResult result = FsRandomAccessFile::Constructor(); + if (!result.IsSuccess()) { + HILOGE("Failed to instantiate class"); + return FsResult::Error(EIO); + } + + const FsRandomAccessFile *objRAF = result.GetData().value(); + if (!objRAF) { + HILOGE("Cannot instantiate randomaccessfile"); + return FsResult::Error(EIO); + } + + auto *rafEntity = objRAF->GetRAFEntity(); + if (!rafEntity) { + HILOGE("Cannot instantiate randomaccessfile because of void entity"); + return FsResult::Error(EIO); + } + rafEntity->fd.swap(fdg); + rafEntity->filePointer = fp; + rafEntity->start = start; + rafEntity->end = end; + return result; +} + +FsResult CreateRandomAccessFileCore::DoCreateRandomAccessFile( + const string &path, const optional &mode, const optional &options) +{ + auto [succ, fileInfo, err] = ParseStringToFileInfo(path); + if (!succ) { + return FsResult::Error(err); + } + + auto [succFlags, flags, ignoreStart, ignoreEnd] = ValidAndConvertFlags(mode, options, fileInfo); + if (!succFlags) { + return FsResult::Error(EINVAL); + } + + unique_ptr openReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!openReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + int ret = uv_fs_open(nullptr, openReq.get(), fileInfo.path.get(), flags, S_IRUSR | + S_IWUSR | S_IRGRP | S_IWGRP, NULL); + if (ret < 0) { + return FsResult::Error(ret); + } + + fileInfo.fdg->SetFD(openReq.get()->result, false); + + if (options.has_value()) { + auto [succ, start, end] = ValidRafOptions(options); + if (succ) { + return InstantiateRandomAccessFile(move(fileInfo.fdg), 0, start, end); + } + } + return InstantiateRandomAccessFile(move(fileInfo.fdg), 0); +} + +FsResult CreateRandomAccessFileCore::DoCreateRandomAccessFile( + const int32_t &fd, const optional &options) +{ + auto [succ, fileInfo, err] = ParseFdToFileInfo(fd); + if (!succ) { + return FsResult::Error(err); + } + if (options.has_value()) { + auto [succ, start, end] = ValidRafOptions(options); + if (succ) { + return InstantiateRandomAccessFile(move(fileInfo.fdg), 0, start, end); + } + } + return InstantiateRandomAccessFile(move(fileInfo.fdg), 0); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile_core.h b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile_core.h new file mode 100644 index 0000000000000000000000000000000000000000..aa7b3a2b0da86b1816f7a065843496728977ab2e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_randomaccessfile_core.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 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_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_RANDOMACCESSFILE_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_file.h" +#include "fs_randomaccessfile.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct RandomAccessFileOptions { + optional start = nullopt; + optional end = nullopt; +}; + +class CreateRandomAccessFileCore final { +public: + static FsResult DoCreateRandomAccessFile( + const string &path, const optional &mode = nullopt, + const optional &options = nullopt); + static FsResult DoCreateRandomAccessFile( + const int32_t &fd, const optional &options = nullopt); +}; +const string PROCEDURE_CREATERAT_NAME = "FileIOCreateRandomAccessFile"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_RANDOMACCESSFILE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/create_stream_core.cpp b/interfaces/kits/js/src/mod_fs/properties/create_stream_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e17d5a1ba01ff3880d99d8cabe5a96dcd5f962e6 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_stream_core.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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_core.h" + +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" +#include "stream_instantiator.h" +#include "stream_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult CreateStreamCore::DoCreateStream(const std::string &path, const std::string &mode) +{ + FILE *file = fopen(path.c_str(), mode.c_str()); + if (!file) { + HILOGE("Failed to fopen file by path"); + return FsResult::Error(errno); + } + + return StreamInstantiator::InstantiateStream(move(file)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/create_stream_core.h b/interfaces/kits/js/src/mod_fs/properties/create_stream_core.h new file mode 100644 index 0000000000000000000000000000000000000000..8c0a2aade48bf44ad726e580d500a099d2ad086c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/create_stream_core.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_stream.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class CreateStreamCore final { +public: + static FsResult DoCreateStream(const std::string &path, const std::string &mode); +}; + +struct AsyncCreateStreamArg { + std::shared_ptr fp { nullptr }; +}; + +const std::string PROCEDURE_CREATESTREAM_NAME = "FileIOCreateStream"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_CREATE_STREAM_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/dup_core.cpp b/interfaces/kits/js/src/mod_fs/properties/dup_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7162051499842faad86ee99d5b1a9f176ca5756b --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/dup_core.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 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 "dup_core.h" + +#include +#include +#include +#include + +#include "file_entity.h" +#include "file_instantiator.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static bool ValidFd(const int32_t &fd) +{ + if (fd < 0) { + HILOGE("Invalid fd"); + return false; + } + return true; +} + +FsResult DupCore::DoDup(const int32_t &fd) +{ + if (!ValidFd(fd)) { + return FsResult::Error(EINVAL); + } + int dstFd = dup(fd); + if (dstFd < 0) { + HILOGE("Failed to dup fd, errno: %{public}d", errno); + return FsResult::Error(errno); + } + unique_ptr readLinkReq = { + new (std::nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (!readLinkReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + string path = "/proc/self/fd/" + to_string(dstFd); + int ret = uv_fs_readlink(nullptr, readLinkReq.get(), path.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to readlink fd, ret: %{public}d", ret); + return FsResult::Error(ret); + } + return FileInstantiator::InstantiateFile(dstFd, string(static_cast(readLinkReq->ptr)), false); +} +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/dup_core.h b/interfaces/kits/js/src/mod_fs/properties/dup_core.h new file mode 100644 index 0000000000000000000000000000000000000000..074d07a8e2e400e969d8503377eda9d78823316d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/dup_core.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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_DUP_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_DUP_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_file.h" + +namespace OHOS::FileManagement::ModuleFileIO { +class DupCore final { +public: + static FsResult DoDup(const int32_t &fd); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_DUP_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fdatasync_core.cpp b/interfaces/kits/js/src/mod_fs/properties/fdatasync_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..57b479f2bf329f2cd5a97e4852e32d906bc69bcc --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fdatasync_core.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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 "fdatasync_core.h" + +#include +#include +#include +#include +#include + +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +FsResult FDataSyncCore::DoFDataSync(const int32_t &fd) +{ + std::unique_ptr fDataSyncReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!fDataSyncReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + int ret = uv_fs_fdatasync(nullptr, fDataSyncReq.get(), fd, nullptr); + if (ret < 0) { + HILOGE("Failed to transfer data associated with file descriptor: %{public}d, ret:%{public}d", fd, ret); + return FsResult::Error(ret); + } + + return FsResult::Success(); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fdatasync_core.h b/interfaces/kits/js/src/mod_fs/properties/fdatasync_core.h new file mode 100644 index 0000000000000000000000000000000000000000..8efb6f90722e0f6c342d58c293a84995ac1efda5 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fdatasync_core.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 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_FDATASYNC_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDATASYNC_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +class FDataSyncCore final { +public: + static FsResult DoFDataSync(const int32_t &fd); +}; +const std::string PROCEDURE_FDATASYNC_NAME = "FileIOFdatasync"; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDATASYNC_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fdopen_stream_core.cpp b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4337cd766b644ce8949f7643ff2816c8013f386d --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream_core.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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_core.h" + +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" +#include "stream_instantiator.h" +#include "stream_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult FdopenStreamCore::DoFdopenStream(const int &fd, const string &mode) +{ + if (fd < 0) { + HILOGE("Invalid fd"); + return FsResult::Error(EINVAL); + } + + FILE *file = fdopen(fd, mode.c_str()); + if (!file) { + HILOGE("Failed to fopen file by fd"); + return FsResult::Error(errno); + } + + return StreamInstantiator::InstantiateStream(move(file)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fdopen_stream_core.h b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream_core.h new file mode 100644 index 0000000000000000000000000000000000000000..a319480fdd0c2aad52dc938f1b0512cc529776e6 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fdopen_stream_core.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2025 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_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDOPEN_STREAM_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_stream.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class FdopenStreamCore final { +public: + static FsResult DoFdopenStream(const int &fd, const string &mode); +}; + +struct AsyncFdopenStreamArg { + std::shared_ptr fp { nullptr }; +}; + +const std::string PROCEDURE_FDOPENSTREAM_NAME = "FileIOFdopenStream"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FDOPEN_STREAM_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fsync_core.cpp b/interfaces/kits/js/src/mod_fs/properties/fsync_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d902ff1f31e2dc4aa125bffbbff40378278b8ecc --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fsync_core.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2025 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 "fsync_core.h" + +#include +#include +#include + +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +FsResult FsyncCore::DoFsync(const int32_t &fd) +{ + std::unique_ptr fsyncReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!fsyncReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_fsync(nullptr, fsyncReq.get(), fd, nullptr); + if (ret < 0) { + HILOGE("Failed to transfer data associated with file descriptor: %{public}d", fd); + return FsResult::Error(ret); + } + return FsResult::Success(); +} +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/fsync_core.h b/interfaces/kits/js/src/mod_fs/properties/fsync_core.h new file mode 100644 index 0000000000000000000000000000000000000000..ce2b6683555e973823b80a0582bb8e9a66e3f322 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/fsync_core.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2025 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_FSYNC_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FSYNC_CORE_H + +#include "filemgmt_libfs.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +class FsyncCore final { +public: + static FsResult DoFsync(const int32_t &fd); +}; +const std::string PROCEDURE_FSYNC_NAME = "FileIOFsync"; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_FSYNC_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/listfile_core.cpp b/interfaces/kits/js/src/mod_fs/properties/listfile_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d334c8a47a11a6165ce4c65a41a78408f976d9f --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/listfile_core.cpp @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2025 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 "listfile_core.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +thread_local OptionArgs g_optionArgsCore; + +static bool CheckSuffix(const vector &suffixs) +{ + for (string suffix : suffixs) { + if (suffix.length() <= 1 || suffix.length() > MAX_SUFFIX_LENGTH) { + return false; + } + if (suffix[0] != '.') { + return false; + } + for (size_t i = 1; i < suffix.length(); i++) { + if (!isalnum(suffix[i])) { + return false; + } + } + } + return true; +} + +static bool ValidFileFilterParam(FsFileFilter &fsFilter, FileFilter *filter) +{ + auto suffixs = fsFilter.GetSuffix(); + if (fsFilter.GetSuffix().has_value()) { + vector suffixs = fsFilter.GetSuffix().value(); + if (!CheckSuffix(suffixs) || suffixs.size() == 0) { + HILOGE("Invalid suffix."); + return false; + } + filter->SetSuffix(suffixs); + } + + if (fsFilter.GetDisplayName().has_value()) { + vector displayNames = fsFilter.GetDisplayName().value(); + if (displayNames.size() == 0) { + HILOGE("Invalid displayName."); + return false; + } + filter->SetDisplayName(displayNames); + } + + if (fsFilter.GetFileSizeOver().has_value()) { + int64_t fileSizeOver = fsFilter.GetFileSizeOver().value(); + if (fileSizeOver < 0) { + HILOGE("Failed to get fileSizeOver prop."); + return false; + } + filter->SetFileSizeOver(fileSizeOver); + } + + if (fsFilter.GetLastModifiedAfter().has_value()) { + double lastModifiedAfter = fsFilter.GetLastModifiedAfter().value(); + if (lastModifiedAfter < 0) { + HILOGE("Failed to get lastModifiedAfter prop."); + return false; + } + filter->SetLastModifiedAfter(lastModifiedAfter); + } + + return true; +} + +static bool ValidOptionParam(const string &path, const optional &opt, OptionArgs &optionArgs) +{ + g_optionArgsCore.Clear(); + g_optionArgsCore.path = path; + + if (opt.has_value()) { + auto op = opt.value(); + if (op.listNum < 0) { + HILOGE("Failed to get listNum prop"); + return false; + } + + optionArgs.recursion = op.recursion; + optionArgs.listNum = op.listNum; + + if (op.filter.has_value()) { + bool ret = ValidFileFilterParam(op.filter.value(), &(optionArgs.filter)); + if (!ret) { + HILOGE("Failed to get filter prop."); + return false; + } + } + } + + return true; +} + +static bool FilterSuffix(const vector &suffixs, const struct dirent &filename) +{ + if (filename.d_type == DT_DIR) { + return true; + } + size_t found = string(filename.d_name).rfind('.'); + if (found == std::string::npos) { + return false; + } + string suffixStr = string(filename.d_name).substr(found); + for (const auto &iter : suffixs) { + if (iter == suffixStr) { + return true; + } + } + return false; +} + +static bool FilterDisplayname(const vector &displaynames, const struct dirent &filename) +{ + for (const auto &iter : displaynames) { + int ret = fnmatch(iter.c_str(), filename.d_name, FNM_PATHNAME | FNM_PERIOD); + if (ret == 0) { + return true; + } + } + return false; +} + +static bool FilterFilesizeOver(const int64_t fFileSizeOver, const struct dirent &filename) +{ + if (fFileSizeOver < 0) { + return true; + } + struct stat info; + string stPath = (g_optionArgsCore.path + '/' + string(filename.d_name)); + int32_t res = stat(stPath.c_str(), &info); + if (res != 0) { + HILOGE("Failed to stat file."); + return false; + } + if (info.st_size > fFileSizeOver) { + return true; + } + return false; +} + +static bool FilterLastModifyTime(const double lastModifiedAfter, const struct dirent &filename) +{ + if (lastModifiedAfter < 0) { + return true; + } + struct stat info; + string stPath = g_optionArgsCore.path + '/' + string(filename.d_name); + int32_t res = stat(stPath.c_str(), &info); + if (res != 0) { + HILOGE("Failed to stat file."); + return false; + } + if (static_cast(info.st_mtime) > lastModifiedAfter) { + return true; + } + return false; +} + +static bool FilterResult(const struct dirent &filename) +{ + vector fSuffixs = g_optionArgsCore.filter.GetSuffix(); + if (!FilterSuffix(fSuffixs, filename) && fSuffixs.size() > 0) { + return false; + } + vector fDisplaynames = g_optionArgsCore.filter.GetDisplayName(); + if (!FilterDisplayname(fDisplaynames, filename) && fDisplaynames.size() > 0) { + return false; + } + int64_t fFileSizeOver = g_optionArgsCore.filter.GetFileSizeOver(); + if (!FilterFilesizeOver(fFileSizeOver, filename)) { + return false; + } + double fLastModifiedAfter = g_optionArgsCore.filter.GetLastModifiedAfter(); + if (!FilterLastModifyTime(fLastModifiedAfter, filename)) { + return false; + } + g_optionArgsCore.countNum++; + return true; +} + +static int32_t FilterFunc(const struct dirent *filename) +{ + if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") { + return FILTER_DISMATCH; + } + + if (g_optionArgsCore.countNum < g_optionArgsCore.listNum || g_optionArgsCore.listNum == 0) { + if ((filename->d_type == DT_DIR && g_optionArgsCore.recursion) || FilterResult(*filename)) { + return FILTER_MATCH; + } + } + return FILTER_DISMATCH; +} + +static void Deleter(struct NameListArg *arg) +{ + for (int i = 0; i < arg->direntNum; i++) { + free((arg->namelist)[i]); + (arg->namelist)[i] = nullptr; + } + free(arg->namelist); + arg->namelist = nullptr; + delete arg; + arg = nullptr; +} + +static int FilterFileRes(const string &path, vector &dirents) +{ + unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; + if (!pNameList) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, nullptr); + if (num < 0) { + HILOGE("Failed to scan dir"); + return errno; + } + pNameList->direntNum = num; + for (int i = 0; i < num; i++) { + dirents.emplace_back(pNameList->namelist[i]->d_name); + } + return ERRNO_NOERR; +} + +static int RecursiveFunc(const string &path, vector &dirents) +{ + unique_ptr pNameList = { new (nothrow) struct NameListArg, Deleter }; + if (!pNameList) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, nullptr); + if (num < 0) { + HILOGE("Failed to scan dir"); + return errno; + } + pNameList->direntNum = num; + for (int i = 0; i < num; i++) { + if ((*(pNameList->namelist[i])).d_type == DT_REG) { + dirents.emplace_back(path + '/' + pNameList->namelist[i]->d_name); + } else if ((*(pNameList->namelist[i])).d_type == DT_DIR) { + string pathTemp = g_optionArgsCore.path; + g_optionArgsCore.path += '/' + string((*(pNameList->namelist[i])).d_name); + int ret = RecursiveFunc(g_optionArgsCore.path, dirents); + if (ret != ERRNO_NOERR) { + return ret; + } + g_optionArgsCore.path = pathTemp; + } + } + return ERRNO_NOERR; +} + +static void DoListFileVector(const string &path, vector &dirents, bool recursion) +{ + if (recursion) { + for (size_t i = 0; i < dirents.size(); i++) { + dirents[i] = dirents[i].substr(path.length()); + } + } +} + +FsResult> ListFileCore::DoListFile(const string &path, const optional &opt) +{ + if (!ValidOptionParam(path, opt, g_optionArgsCore)) { + HILOGE("Invalid options"); + return FsResult>::Error(EINVAL); + } + + vector direntsRes; + int ret = 0; + ret = g_optionArgsCore.recursion ? RecursiveFunc(path, direntsRes) : FilterFileRes(path, direntsRes); + if (ret) { + return FsResult>::Error(ret); + } + DoListFileVector(path, direntsRes, g_optionArgsCore.recursion); + g_optionArgsCore.Clear(); + + return FsResult>::Success(direntsRes); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/listfile_core.h b/interfaces/kits/js/src/mod_fs/properties/listfile_core.h new file mode 100644 index 0000000000000000000000000000000000000000..5299762c9fceae2391df3bd306f244b3eecac15a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/listfile_core.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2025 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_LISTFILE_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_LISTFILE_CORE_H + +#include + +#include "file_filter.h" +#include "filemgmt_libfs.h" +#include "fs_file_filter.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +struct NameListArg { + struct dirent **namelist = { nullptr }; + int direntNum = 0; +}; + +constexpr int DEFAULT_SIZE = -1; +constexpr int DEFAULT_MODIFY_AFTER = -1; +struct OptionArgs { + FileFilter filter = + FileFilterBuilder().SetFileSizeOver(DEFAULT_SIZE).SetLastModifiedAfter(DEFAULT_MODIFY_AFTER).Build(); + int listNum = 0; + int countNum = 0; + bool recursion = false; + std::string path = ""; + void Clear() + { + filter.FilterClear(); + filter.SetFileSizeOver(DEFAULT_SIZE); + filter.SetLastModifiedAfter(DEFAULT_MODIFY_AFTER); + listNum = 0; + countNum = 0; + recursion = false; + path = ""; + } +}; + +struct FsListFileOptions { + bool recursion = false; + int64_t listNum = 0; + optional filter = nullopt; +}; + +class ListFileCore { +public: + static FsResult> DoListFile( + const std::string &path, const optional &opt = nullopt); +}; + +constexpr int FILTER_MATCH = 1; +constexpr int FILTER_DISMATCH = 0; +const int32_t MAX_SUFFIX_LENGTH = 256; +const std::string LIST_FILE_PRODUCE_NAME = "FileIOListFile"; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_LISTFILE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/lseek_core.cpp b/interfaces/kits/js/src/mod_fs/properties/lseek_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfec873c9cf2bea50fb4fb2932408c95ca116a2c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/lseek_core.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2025 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 "lseek_core.h" + +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult LseekCore::DoLseek(const int32_t &fd, const int64_t &offset, + const optional &pos) +{ + if (fd < 0) { + HILOGE("Invalid fd from JS first argument"); + return FsResult::Error(EINVAL); + } + + SeekPos whence = SeekPos::START; + if (pos.has_value()) { + if (pos.value() < SeekPos::START || pos.value() > SeekPos::END) { + HILOGE("Invalid whence from JS third argument"); + return FsResult::Error(EINVAL); + } + whence = pos.value(); + } + + int64_t ret = ::Lseek(fd, offset, whence); + if (ret < 0) { + HILOGE("Failed to lseek, error:%{public}d", errno); + return FsResult::Error(errno); + } + + return FsResult::Success(ret); +} + +} // ModuleFileIO +} // FileManagement +} // OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/lseek_core.h b/interfaces/kits/js/src/mod_fs/properties/lseek_core.h new file mode 100644 index 0000000000000000000000000000000000000000..dd399f652e37dbe23edc17b24be32b74d1f19536 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/lseek_core.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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_LSEEK_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_LSEEK_CORE_H + +#include "filemgmt_libfs.h" +#include "rust_file.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +class LseekCore final { +public: + static FsResult DoLseek(const int32_t &fd, const int64_t &offset, + const optional &pos = nullopt); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_LSEEK_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/lstat_core.cpp b/interfaces/kits/js/src/mod_fs/properties/lstat_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cef683a91b59f9598e8505add9c68238351632fe --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/lstat_core.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 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 "lstat_core.h" + +#include +#include + +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "stat_instantiator.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +FsResult LstatCore::DoLstat(const string &path) +{ + std::unique_ptr lstat_req = { new (std::nothrow) uv_fs_t, + FsUtils::FsReqCleanup }; + if (!lstat_req) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_lstat(nullptr, lstat_req.get(), path.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to get stat of file, ret: %{public}d", ret); + return FsResult::Error(ret); + } + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + size_t length = path.length() + 1; + auto chars = std::make_unique(length); + ret = strncpy_s(chars.get(), length, path.c_str(), length - 1); + if (ret != EOK) { + HILOGE("Copy file path failed!"); + return FsResult::Error(ret); + } + struct FileInfo info = { true, move(chars), {} }; + auto arg = CreateSharedPtr(move(info)); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + auto stat = StatInstantiator::InstantiateStat(lstat_req->statbuf, arg); +#else + auto stat = StatInstantiator::InstantiateStat(lstat_req->statbuf); +#endif + if (stat == nullptr) { + return FsResult::Error(ENOMEM); + } + return FsResult::Success(stat); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/lstat_core.h b/interfaces/kits/js/src/mod_fs/properties/lstat_core.h new file mode 100644 index 0000000000000000000000000000000000000000..8f95142b856da8934c0b7303dbd87ca0342d3674 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/lstat_core.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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_LSTAT_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_LSTAT_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_stat.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +class LstatCore final { +public: + static FsResult DoLstat(const string &path); +}; +const std::string PROCEDURE_LSTAT_NAME = "FileIOLstat"; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_LSTAT_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/mkdir_core.cpp b/interfaces/kits/js/src/mod_fs/properties/mkdir_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..203ead742fda8d818fec8031e45a0118a1436bd9 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/mkdir_core.cpp @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2025 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 "mkdir_core.h" + +#include +#include +#include +#include +#include +#include + +#include "filemgmt_libhilog.h" + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +#include + +#include "bundle_mgr_proxy.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "rust_file.h" +#include "system_ability_definition.h" +#endif + +#ifdef FILE_API_TRACE +#include "hitrace_meter.h" +#endif + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +using namespace AppExecFwk; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +const string CLOUDDISK_FILE_PREFIX = "/data/storage/el2/cloud"; +const string DISTRIBUTED_FILE_PREFIX = "/data/storage/el2/distributedfiles"; +const string PACKAGE_NAME_FLAG = ""; +const string USER_ID_FLAG = ""; +const string PHYSICAL_PATH_PREFIX = "/mnt/hmdfs//account/device_view/local/data/"; +const string CLOUD_FILE_LOCATION = "user.cloud.location"; +const char POSITION_LOCAL = '1'; +const char POSITION_BOTH = '3'; +const int BASE_USER_RANGE = 200000; +#endif + +enum AccessFlag : int32_t { + DEFAULT_FLAG = -1, + LOCAL_FLAG, +}; + +struct AccessArgs { + string path; + int mode = -1; + int flag = DEFAULT_FLAG; +}; + +static int UvAccess(const string &path, int mode) +{ + std::unique_ptr access_req = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!access_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + return uv_fs_access(nullptr, access_req.get(), path.c_str(), mode, nullptr); +} + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +static bool IsCloudOrDistributedFilePath(const string &path) +{ + return path.find(CLOUDDISK_FILE_PREFIX) == 0 || path.find(DISTRIBUTED_FILE_PREFIX) == 0; +} + +static int GetCurrentUserId() +{ + int uid = IPCSkeleton::GetCallingUid(); + int userId = uid / BASE_USER_RANGE; + return userId; +} + +static sptr GetBundleMgrProxy() +{ + sptr systemAbilityManager = + SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + if (!systemAbilityManager) { + HILOGE("fail to get system ability mgr"); + return nullptr; + } + sptr remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID); + if (!remoteObject) { + HILOGE("fail to get bundle manager proxy"); + return nullptr; + } + + return iface_cast(remoteObject); +} + +static string GetSelfBundleName() +{ + sptr bundleMgrProxy = GetBundleMgrProxy(); + if (!bundleMgrProxy) { + HILOGE("bundleMgrProxy is nullptr"); + return ""; + } + BundleInfo bundleInfo; + auto ret = bundleMgrProxy->GetBundleInfoForSelf(0, bundleInfo); + if (ret != 0) { + HILOGE("bundleName get fail"); + return ""; + } + return bundleInfo.name; +} + +static int HandleLocalCheck(const string &path, int mode) +{ + // check if the file of /data/storage/el2/cloud is on the local + if (path.find(CLOUDDISK_FILE_PREFIX) == 0) { + char val[2] = { '\0' }; + if (getxattr(path.c_str(), CLOUD_FILE_LOCATION.c_str(), val, sizeof(val)) < 0) { + HILOGI("get cloud file location fail, err: %{public}d", errno); + return errno; + } + if (val[0] == POSITION_LOCAL || val[0] == POSITION_BOTH) { + return 0; + } + return ENOENT; + } + // check if the distributed file of /data/storage/el2/distributedfiles is on the local, + // convert into physical path(/mnt/hmdfs//account/device_view/local/data/) and check + if (path.find(DISTRIBUTED_FILE_PREFIX) == 0) { + int userId = GetCurrentUserId(); + string bundleName = GetSelfBundleName(); + string relativePath = path.substr(DISTRIBUTED_FILE_PREFIX.length()); + string physicalPath = PHYSICAL_PATH_PREFIX + relativePath; + physicalPath.replace(physicalPath.find(USER_ID_FLAG), USER_ID_FLAG.length(), to_string(userId)); + physicalPath.replace(physicalPath.find(PACKAGE_NAME_FLAG), PACKAGE_NAME_FLAG.length(), bundleName); + + return UvAccess(physicalPath, mode); + } + + return ENOENT; +} +#endif + +static int AccessCore(const string &path, int mode, int flag = DEFAULT_FLAG) +{ +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + if (flag == LOCAL_FLAG && IsCloudOrDistributedFilePath(path)) { + return HandleLocalCheck(path, mode); + } +#endif + return UvAccess(path, mode); +} + +static int MkdirCore(const string &path) +{ + std::unique_ptr mkdir_req = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!mkdir_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + return uv_fs_mkdir(nullptr, mkdir_req.get(), path.c_str(), DIR_DEFAULT_PERM, nullptr); +} + +static int32_t MkdirExec(const string &path, bool recursion, bool hasOption) +{ +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + if (hasOption) { + int ret = AccessCore(path, 0); + if (ret == ERRNO_NOERR) { + HILOGD("The path already exists"); + return EEXIST; + } + if (ret != -ENOENT) { + HILOGE("Failed to check for illegal path or request for heap memory"); + return ret; + } + if (::Mkdirs(path.c_str(), static_cast(recursion)) < 0) { + HILOGD("Failed to create directories, error: %{public}d", errno); + return errno; + } + ret = AccessCore(path, 0); + if (ret) { + HILOGE("Failed to verify the result of Mkdirs function"); + return ret; + } + return ERRNO_NOERR; + } +#endif + int ret = MkdirCore(path); + if (ret) { + HILOGD("Failed to create directory"); + return ret; + } + return ERRNO_NOERR; +} + +FsResult MkdirCore::DoMkdir(const std::string &path, std::optional recursion) +{ + bool hasOption = false; + bool mkdirRecursion = false; +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + hasOption = recursion.has_value(); + if (hasOption) { + mkdirRecursion = recursion.value(); + } +#endif + auto err = MkdirExec(path, mkdirRecursion, hasOption); + if (err) { + return FsResult::Error(err); + } + return FsResult::Success(); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/mkdir_core.h b/interfaces/kits/js/src/mod_fs/properties/mkdir_core.h new file mode 100644 index 0000000000000000000000000000000000000000..cc6793693dca3c355419aae57de9ccaaf7749d9a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/mkdir_core.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDIR_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDIR_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class MkdirCore final { +public: + static FsResult DoMkdir(const std::string& path, std::optional recursion = std::nullopt); +}; +constexpr int DIR_DEFAULT_PERM = 0770; +const std::string PROCEDURE_READTEXT_NAME = "FileIOMkdir"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDIR_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.cpp b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..487f35c69e38f90b309425a64e7b16ae4b4ae33e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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 "mkdtemp_core.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult MkdtempCore::DoMkdtemp(const string &path) +{ + unique_ptr mkdtempReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!mkdtempReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_mkdtemp(nullptr, mkdtempReq.get(), const_cast(path.c_str()), nullptr); + if (ret < 0) { + HILOGE("Failed to create a temporary directory with path"); + return FsResult::Error(ret); + } + + return FsResult::Success(move(mkdtempReq->path)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.h b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.h new file mode 100644 index 0000000000000000000000000000000000000000..e638655ba71a3985d200fdb6e360e872d49a5fc0 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_MKDTEMP_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDTEMP_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class MkdtempCore final { +public: + static FsResult DoMkdtemp(const std::string &path); +}; +const std::string PROCEDURE_MKDTEMP_NAME = "FileIOMkdtemp"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDTEMP_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/move_core.cpp b/interfaces/kits/js/src/mod_fs/properties/move_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1b1100dec3bd3b39d87d9b7e084765765eede08 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/move_core.cpp @@ -0,0 +1,188 @@ +/* +* Copyright (c) 2025 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 "move_core.h" + +#ifdef __MUSL__ +#include +#else +#include +#endif + +#include +#include + +#include "filemgmt_libhilog.h" +#include "uv.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +#ifdef __MUSL__ +static bool CheckDir(const string &path) +{ + error_code errCode; + if (!filesystem::is_directory(filesystem::status(path, errCode))) { + return false; + } + return true; +} +#else +static bool CheckDir(const string &path) +{ + struct stat fileInformation; + if (stat(path.c_str(), &fileInformation) == 0) { + if (fileInformation.st_mode & S_IFDIR) { + return true; + } + } else { + HILOGE("Failed to stat file"); + } + return false; +} +#endif + +static tuple ValidMoveArg(const string &src, const string &dest, const optional &mode) +{ + if (CheckDir(src)) { + HILOGE("Invalid src"); + return { false, nullptr, nullptr, 0 }; + } + if (CheckDir(dest)) { + HILOGE("Invalid dest"); + return { false, nullptr, nullptr, 0 }; + } + int modeType = 0; + if (mode.has_value()) { + modeType = mode.value(); + if ((modeType != MODE_FORCE_MOVE && modeType != MODE_THROW_ERR)) { + HILOGE("Invalid mode"); + return { false, nullptr, nullptr, 0 }; + } + } + return { true, move(src), move(dest), modeType }; +} + +static int CopyAndDeleteFile(const string &src, const string &dest) +{ + unique_ptr stat_req = { + new (nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (!stat_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_stat(nullptr, stat_req.get(), src.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to stat srcPath"); + return ret; + } +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + filesystem::path dstPath(dest); + error_code errCode; + if (filesystem::exists(dstPath, errCode)) { + if (!filesystem::remove(dstPath, errCode)) { + HILOGE("Failed to remove dest file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + } + filesystem::path srcPath(src); + if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) { + HILOGE("Failed to copy file, error code: %{public}d", errCode.value()); + return errCode.value(); + } +#else + uv_fs_t copyfile_req; + ret = uv_fs_copyfile(nullptr, ©file_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr); + uv_fs_req_cleanup(©file_req); + if (ret < 0) { + HILOGE("Failed to move file using copyfile interface."); + return ret; + } +#endif + uv_fs_t unlink_req; + ret = uv_fs_unlink(nullptr, &unlink_req, src.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to unlink src file"); + int result = uv_fs_unlink(nullptr, &unlink_req, dest.c_str(), nullptr); + if (result < 0) { + HILOGE("Failed to unlink dest file"); + return result; + } + uv_fs_req_cleanup(&unlink_req); + return ret; + } + uv_fs_req_cleanup(&unlink_req); + return ERRNO_NOERR; +} + +static int RenameFile(const string &src, const string &dest) +{ + int ret = 0; + uv_fs_t rename_req; + ret = uv_fs_rename(nullptr, &rename_req, src.c_str(), dest.c_str(), nullptr); + if (ret < 0 && (string_view(uv_err_name(ret)) == "EXDEV")) { + return CopyAndDeleteFile(src, dest); + } + if (ret < 0) { + HILOGE("Failed to move file using rename syscall."); + return ret; + } + return ERRNO_NOERR; +} + +static int MoveFile(const string &src, const string &dest, int mode) +{ + uv_fs_t access_req; + int ret = uv_fs_access(nullptr, &access_req, src.c_str(), W_OK, nullptr); + if (ret < 0) { + HILOGE("Failed to move src file due to doesn't exist or hasn't write permission"); + uv_fs_req_cleanup(&access_req); + return ret; + } + if (mode == MODE_THROW_ERR) { + ret = uv_fs_access(nullptr, &access_req, dest.c_str(), 0, nullptr); + uv_fs_req_cleanup(&access_req); + if (ret == 0) { + HILOGE("Failed to move file due to existing destPath with MODE_THROW_ERR."); + return EEXIST; + } + if (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) { + HILOGE("Failed to access destPath with MODE_THROW_ERR."); + return ret; + } + } else { + uv_fs_req_cleanup(&access_req); + } + return RenameFile(src, dest); +} + +FsResult MoveCore::DoMove(const string &src, const string &dest, const optional &mode) +{ + auto [succ, srcPath, destPath, modeType] = ValidMoveArg(src, dest, mode); + if (!succ) { + return FsResult::Error(EINVAL); + } + int ret = MoveFile(move(srcPath), move(destPath), modeType); + if (ret) { + return FsResult::Error(ret); + } + return FsResult::Success(); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/move_core.h b/interfaces/kits/js/src/mod_fs/properties/move_core.h new file mode 100644 index 0000000000000000000000000000000000000000..6b479fcd8dbdf7ac3783c0fc19b2aa4f9561d3ad --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/move_core.h @@ -0,0 +1,38 @@ +/* +* Copyright (c) 2025 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_MOVE_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MOVE_CORE_H + +#include +#include "fs_utils.h" +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class MoveCore final { +public: + static FsResult DoMove(const std::string &src, + const std::string &dest, + const std::optional &mode = std::nullopt); +}; +constexpr int MODE_FORCE_MOVE = 0; +constexpr int MODE_THROW_ERR = 1; +const std::string PROCEDURE_MOVE_NAME = "FileIOMove"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/movedir_core.cpp b/interfaces/kits/js/src/mod_fs/properties/movedir_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb357ff05a3a69c00db190eb57a16472988fd709 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/movedir_core.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2025 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 "movedir_core.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode, + deque &errfiles); + +static tuple JudgeExistAndEmpty(const string &path) +{ + std::error_code errCode; + filesystem::path pathName(path); + if (filesystem::exists(pathName, errCode)) { + if (filesystem::is_empty(pathName, errCode)) { + return { true, true }; + } + return { true, false }; + } + return { false, false }; +} + +static int RmDirectory(const string &path) +{ + filesystem::path pathName(path); + std::error_code errCode; + if (filesystem::exists(pathName, errCode)) { + std::error_code errCode; + (void)filesystem::remove_all(pathName, errCode); + if (errCode.value() != 0) { + HILOGE("Failed to remove directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + } else if (errCode.value() != ERRNO_NOERR) { + HILOGE("fs exists fail, errcode is %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +static int RemovePath(const string& pathStr) +{ + filesystem::path pathTarget(pathStr); + std::error_code errCode; + if (!filesystem::remove(pathTarget, errCode)) { + HILOGE("Failed to remove file or directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +static int CopyAndDeleteFile(const string &src, const string &dest) +{ + filesystem::path dstPath(dest); + std::error_code errCode; + if (filesystem::exists(dstPath, errCode)) { + int removeRes = RemovePath(dest); + if (removeRes != 0) { + HILOGE("Failed to remove dest file"); + return removeRes; + } + } + filesystem::path srcPath(src); + if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) { + HILOGE("Failed to copy file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return RemovePath(src); +} + +static int RenameFile(const string &src, const string &dest, const int mode, deque &errfiles) +{ + filesystem::path dstPath(dest); + std::error_code errCode; + if (filesystem::exists(dstPath, errCode)) { + if (filesystem::is_directory(dstPath, errCode)) { + errfiles.emplace_front(src, dest); + return ERRNO_NOERR; + } + if (mode == DIRMODE_FILE_THROW_ERR) { + errfiles.emplace_back(src, dest); + return ERRNO_NOERR; + } + } + if (errCode.value() != ERRNO_NOERR) { + HILOGE("fs exists or is_directory fail, errcode is %{public}d", errCode.value()); + } + filesystem::path srcPath(src); + filesystem::rename(srcPath, dstPath, errCode); + if (errCode.value() == EXDEV) { + HILOGD("Failed to rename file due to EXDEV"); + return CopyAndDeleteFile(src, dest); + } + return errCode.value(); +} + +static int32_t FilterFunc(const struct dirent *filename) +{ + if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") { + return FILE_DISMATCH; + } + return FILE_MATCH; +} + +static int RenameDir(const string &src, const string &dest, const int mode, deque &errfiles) +{ + filesystem::path destPath(dest); + std::error_code errCode; + if (filesystem::exists(destPath, errCode)) { + return RecurMoveDir(src, dest, mode, errfiles); + } else if (errCode.value() != ERRNO_NOERR) { + HILOGE("fs exists fail, errcode is %{public}d", errCode.value()); + return errCode.value(); + } + filesystem::path srcPath(src); + filesystem::rename(srcPath, destPath, errCode); + if (errCode.value() == EXDEV) { + HILOGD("Failed to rename file due to EXDEV"); + if (!filesystem::create_directory(destPath, errCode)) { + HILOGE("Failed to create directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return RecurMoveDir(src, dest, mode, errfiles); + } + if (errCode.value() != 0) { + HILOGE("Failed to rename file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +struct NameListArg { + struct dirent** namelist; + int num; +}; + +static void Deleter(struct NameListArg *arg) +{ + for (int i = 0; i < arg->num; i++) { + free((arg->namelist)[i]); + (arg->namelist)[i] = nullptr; + } + free(arg->namelist); + arg->namelist = nullptr; + delete arg; + arg = nullptr; +} + +static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode, + deque &errfiles) +{ + filesystem::path dpath(destPath); + std::error_code errCode; + if (!filesystem::is_directory(dpath, errCode)) { + errfiles.emplace_front(srcPath, destPath); + return ERRNO_NOERR; + } + + unique_ptr ptr = {new struct NameListArg, Deleter}; + if (!ptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(srcPath.c_str(), &(ptr->namelist), FilterFunc, alphasort); + ptr->num = num; + + for (int i = 0; i < num; i++) { + if ((ptr->namelist[i])->d_type == DT_DIR) { + string srcTemp = srcPath + '/' + string((ptr->namelist[i])->d_name); + string destTemp = destPath + '/' + string((ptr->namelist[i])->d_name); + size_t size = errfiles.size(); + int res = RenameDir(srcTemp, destTemp, mode, errfiles); + if (res != ERRNO_NOERR) { + return res; + } + if (size != errfiles.size()) { + continue; + } + res = RemovePath(srcTemp); + if (res) { + return res; + } + } else { + string src = srcPath + '/' + string((ptr->namelist[i])->d_name); + string dest = destPath + '/' + string((ptr->namelist[i])->d_name); + int res = RenameFile(src, dest, mode, errfiles); + if (res != ERRNO_NOERR) { + HILOGE("Failed to rename file for error %{public}d", res); + return res; + } + } + } + return ERRNO_NOERR; +} + +static int MoveDirFunc(const string &src, const string &dest, const int mode, deque &errfiles) +{ + size_t found = string(src).rfind('/'); + if (found == std::string::npos) { + return EINVAL; + } + if (access(src.c_str(), W_OK) != 0) { + HILOGE("Failed to move src directory due to doesn't exist or hasn't write permission"); + return errno; + } + string dirName = string(src).substr(found); + string destStr = dest + dirName; + auto [destStrExist, destStrEmpty] = JudgeExistAndEmpty(destStr); + if (destStrExist && !destStrEmpty) { + if (mode == DIRMODE_DIRECTORY_REPLACE) { + int removeRes = RmDirectory(destStr); + if (removeRes) { + HILOGE("Failed to remove dest directory in DIRMODE_DIRECTORY_REPLACE"); + return removeRes; + } + } + if (mode == DIRMODE_DIRECTORY_THROW_ERR) { + HILOGE("Failed to move directory in DIRMODE_DIRECTORY_THROW_ERR"); + return ENOTEMPTY; + } + } + int res = RenameDir(src, destStr, mode, errfiles); + if (res == ERRNO_NOERR) { + if (!errfiles.empty()) { + HILOGE("Failed to movedir with some conflicted files"); + return EEXIST; + } + int removeRes = RmDirectory(src); + if (removeRes) { + HILOGE("Failed to remove src directory"); + return removeRes; + } + } + return res; +} + +static tuple ValidMoveDirArg( + const string &src, const string &dest, optional mode) +{ + std::error_code errCode; + if (!filesystem::is_directory(filesystem::status(src.c_str(), errCode))) { + HILOGE("Invalid src, errCode = %{public}d", errCode.value()); + return { false, 0 }; + } + if (!filesystem::is_directory(filesystem::status(dest.c_str(), errCode))) { + HILOGE("Invalid dest,errCode = %{public}d", errCode.value()); + return { false, 0 }; + } + int modeType = 0; + if (mode.has_value()) { + modeType = mode.value(); + if (modeType < DIRMODE_MIN || modeType > DIRMODE_MAX) { + HILOGE("Invalid mode"); + return { false, 0 }; + } + } + return { true, modeType }; +} + +MoveDirResult MoveDirCore::DoMoveDir( + const string &src, const string &dest, optional modeType) +{ + auto [succ, mode] = ValidMoveDirArg(src, dest, modeType); + if (!succ) { + return { FsResult::Error(EINVAL), nullopt }; + } + deque errfiles = {}; + int ret = MoveDirFunc(src, dest, mode, errfiles); + if (ret == EEXIST) { + return { FsResult::Error(EEXIST), optional> { errfiles } }; + } else if (ret) { + return { FsResult::Error(ret), nullopt }; + } + return { FsResult::Success(), nullopt }; +} + +} // ModuleFileIO +} // FileManagement +} // OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/movedir_core.h b/interfaces/kits/js/src/mod_fs/properties/movedir_core.h new file mode 100755 index 0000000000000000000000000000000000000000..e4db3553d908beb9d1966a6852d91afd26bd2fe1 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/movedir_core.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2025 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_MOVEDIR_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MOVEDIR_CORE_H + +#include +#include + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +constexpr int DIRMODE_MIN = 0; +constexpr int DIRMODE_MAX = 3; + +constexpr int FILE_DISMATCH = 0; +constexpr int FILE_MATCH = 1; +constexpr int MOVEDIR_DEFAULT_PERM = 0770; + +enum ModeOfMoveDir { + DIRMODE_DIRECTORY_THROW_ERR = 0, + DIRMODE_FILE_THROW_ERR, + DIRMODE_FILE_REPLACE, + DIRMODE_DIRECTORY_REPLACE +}; + +struct ErrFiles { + std::string srcFiles; + std::string destFiles; + ErrFiles(const std::string& src, const std::string& dest) : srcFiles(src), destFiles(dest) {} + ~ErrFiles() = default; +}; + +struct MoveDirResult { + FsResult fsResult; + optional> errFiles; +}; + +class MoveDirCore final { +public: + static MoveDirResult DoMoveDir( + const std::string &src, const std::string &dest, std::optional mode = std::nullopt); +}; + +const std::string PROCEDURE_MOVEDIR_NAME = "FileIOMoveDir"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MOVEDIR_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/open_core.cpp b/interfaces/kits/js/src/mod_fs/properties/open_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45147159fa3ba9e8fe3f4286930672c97c4c2b40 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/open_core.cpp @@ -0,0 +1,202 @@ +/* +* Copyright (c) 2025 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 "open_core.h" + +#include +#include +#include + +#include "file_entity.h" +#include "file_instantiator.h" +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +#include "ability_manager_client.h" +#include "bundle_info.h" +#include "bundle_mgr_proxy.h" +#include "datashare_helper.h" +#include "file_uri.h" +#include "ipc_skeleton.h" +#include "iservice_registry.h" +#include "remote_uri.h" +#include "status_receiver_host.h" +#include "system_ability_definition.h" +#endif + +#ifdef FILE_API_TRACE +#include "hitrace_meter.h" +#endif + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +using namespace OHOS::DistributedFS::ModuleRemoteUri; +using namespace OHOS::AppExecFwk; +#endif + +const std::string PROCEDURE_OPEN_NAME = "FileIOOpen"; +const std::string MEDIALIBRARY_DATA_URI = "datashare:///media"; +const std::string FILE_DATA_URI = "file://"; +const std::string PATH_SHARE = "/data/storage/el2/share"; +const std::string MODE_RW = "/rw/"; +const std::string MODE_R = "/r/"; +const std::string MEDIA = "media"; +const std::string DOCS = "docs"; +const std::string DATASHARE = "datashare"; +const std::string SCHEME_BROKER = "content"; +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) +constexpr uint32_t MAX_WANT_FLAG = 4; +#endif + +static tuple ValidAndConvertFlags(const optional &mode) +{ + uint32_t flags = O_RDONLY; + if (mode.has_value()) { + auto modeValue = mode.value(); + int32_t invalidMode = (O_WRONLY | O_RDWR); + if (modeValue < 0 || ((modeValue & invalidMode) == invalidMode)) { + HILOGE("Invalid mode"); + return { false, flags }; + } + flags = static_cast(modeValue); + (void)FsUtils::ConvertFlags(flags); + } + return { true, flags }; +} + +static int OpenFileByPath(const string &path, uint32_t mode) +{ + unique_ptr openReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!openReq) { + HILOGE("Failed to request heap memory."); + return -ENOMEM; + } + int ret = uv_fs_open(nullptr, openReq.get(), path.c_str(), mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr); + return ret; +} + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + +static int OpenFileByDatashare(const string &path, uint32_t flags) +{ + std::shared_ptr dataShareHelper = nullptr; + sptr remote = new (std::nothrow) IRemoteStub(); + if (!remote) { + HILOGE("Failed to get remote object"); + return -ENOMEM; + } + + dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI); + if (!dataShareHelper) { + HILOGE("Failed to connect to datashare"); + return -E_PERMISSION; + } + Uri uri(path); + int fd = dataShareHelper->OpenFile(uri, FsUtils::GetModeFromFlags(flags)); + return fd; +} + +static tuple OpenByFileDataUri(Uri &uri, const string &uriStr, uint32_t mode) +{ + string bundleName = uri.GetAuthority(); + AppFileService::ModuleFileUri::FileUri fileUri(uriStr); + string realPath = fileUri.GetRealPath(); + if (bundleName == MEDIA) { + int res = OpenFileByDatashare(uri.ToString(), mode); + if (res < 0) { + HILOGE("Failed to open file by Datashare error %{public}d", res); + } + return { res, uri.ToString() }; + } else if (bundleName == DOCS && access(realPath.c_str(), F_OK) != 0) { + int res = OpenFileByDatashare(uri.ToString(), mode); + if (res < 0) { + HILOGE("Failed to open file by Datashare error %{public}d", res); + return { -ENOENT, uri.ToString() }; + } + return { res, uri.ToString() }; + } + int ret = OpenFileByPath(realPath, mode); + if (ret < 0) { + HILOGE("Failed to open file for libuv error %{public}d", ret); + } + return { ret, uriStr }; +} + +static tuple OpenFileByBroker(const Uri &uri, uint32_t mode) +{ + uint32_t flag = (mode % MAX_WANT_FLAG) > 0 ? AAFwk::Want::FLAG_AUTH_WRITE_URI_PERMISSION + : AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION; + int ret = AAFwk::AbilityManagerClient::GetInstance()->OpenFile(uri, flag); + if (ret < 0) { + HILOGE("Failed to open file by Broker error %{public}d", ret); + } + return { ret, uri.ToString() }; +} + +static tuple OpenFileByUri(const string &path, uint32_t mode) +{ + Uri uri(path); + string uriType = uri.GetScheme(); + if (uriType == SCHEME_FILE) { + return OpenByFileDataUri(uri, path, mode); + } + if (uriType == SCHEME_BROKER) { + return OpenFileByBroker(uri, mode); + } + int fd = -1; + if (uriType == DATASHARE && RemoteUri::IsRemoteUri(path, fd, mode)) { + if (fd >= 0) { + return { fd, path }; + } + HILOGE("Failed to open file by RemoteUri"); + } + HILOGE("Failed to open file by invalid uri"); + return { -EINVAL, path }; +} +#endif + +FsResult OpenCore::DoOpen(const string &path, const optional &mode) +{ +#ifdef FILE_API_TRACE + HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__); +#endif + auto [succMode, modeValue] = ValidAndConvertFlags(mode); + if (!succMode) { + return FsResult::Error(EINVAL); + } +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + if (path.find("://") != string::npos) { + auto [res, uriStr] = OpenFileByUri(path, modeValue); + if (res < 0) { + return FsResult::Error(res); + } + return FileInstantiator::InstantiateFile(res, uriStr, true); + } +#endif + int ret = OpenFileByPath(path, modeValue); + if (ret < 0) { + HILOGD("Failed to open file for libuv error %{public}d", ret); + return FsResult::Error(ret); + } + return FileInstantiator::InstantiateFile(ret, path, false); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/open_core.h b/interfaces/kits/js/src/mod_fs/properties/open_core.h new file mode 100644 index 0000000000000000000000000000000000000000..00af19dc77e98e64881d5821689c3da5f46cc6ab --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/open_core.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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_OPEN_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_OPEN_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_file.h" + +namespace OHOS::FileManagement::ModuleFileIO { +class OpenCore final { +public: + static FsResult DoOpen(const std::string &path, const std::optional &mode = std::nullopt); +}; + +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_OPEN_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_core.cpp b/interfaces/kits/js/src/mod_fs/properties/read_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11d7c211e407fe3e7a46da829f813bdb854eb62c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_core.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025 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 "read_core.h" + +#include +#include +#include + +#include + +#include "file_utils.h" +#include "filemgmt_libfs.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static tuple ValidReadArg(ArrayBuffer &arrayBuffer, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + void *buf = arrayBuffer.buf; + size_t bufLen = arrayBuffer.length; + + if (bufLen > UINT_MAX) { + HILOGE("Invalid arraybuffer"); + return { false, nullptr, retLen, offset }; + } + optional lengthOp = nullopt; + optional offsetOp = nullopt; + if (options.has_value()) { + ReadOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + } + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, nullptr, retLen, offset }; + } + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, nullptr, retLen, offset }; + } + } + return { true, buf, retLen, offset }; +} + +FsResult ReadCore::DoRead(const int32_t &fd, ArrayBuffer &arrayBuffer, const optional &options) +{ + if (fd < 0) { + HILOGE("Invalid fd"); + return FsResult::Error(EINVAL); + } + + auto [succ, buf, len, offset] = ValidReadArg(arrayBuffer, options); + if (!succ) { + return FsResult::Error(EINVAL); + } + + uv_buf_t buffer = uv_buf_init(static_cast(buf), static_cast(len)); + unique_ptr readReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!readReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_read(nullptr, readReq.get(), fd, &buffer, 1, offset, nullptr); + if (ret < 0) { + HILOGE("Failed to read file for %{public}d", ret); + return FsResult::Error(ret); + } + + return FsResult::Success(static_cast(ret)); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_core.h b/interfaces/kits/js/src/mod_fs/properties/read_core.h new file mode 100644 index 0000000000000000000000000000000000000000..4b5b74fc3b818e9086d64489417f6dafe6f90493 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_core.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_FILE_API_READ_CORE_H +#define FILEMANAGEMENT_FILE_API_READ_CORE_H + +#include +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +struct ReadOptions final { + optional offset = nullopt; + optional length = nullopt; +}; + +class ReadCore final { +public: + static FsResult DoRead( + const int32_t &fd, ArrayBuffer &arrayBuffer, const optional &options = nullopt); +}; + +const string PROCEDURE_READTEXT_NAME = "FileIOReadText"; +} // namespace OHOS::FileManagement::ModuleFileIO + +#endif // FILEMANAGEMENT_FILE_API_READ_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_lines_core.cpp b/interfaces/kits/js/src/mod_fs/properties/read_lines_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..819215c30e9be4c365a6315fc8e078ade722960e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_lines_core.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 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 "read_lines_core.h" + +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "rust_file.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static int CheckOptionArg(optional option) +{ + auto encoding = option->encoding; + if (encoding != "utf-8") { + return EINVAL; + } + + return ERRNO_NOERR; +} + +static int GetFileSize(const string &path, int64_t &offset) +{ + std::unique_ptr readLinesReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!readLinesReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + + int ret = uv_fs_stat(nullptr, readLinesReq.get(), path.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to get file stat by path"); + return ret; + } + + offset = static_cast(readLinesReq->statbuf.st_size); + return ERRNO_NOERR; +} + +static FsResult InstantiateReaderIterator(void *iterator, int64_t offset) +{ + if (iterator == nullptr) { + HILOGE("Invalid argument iterator"); + return FsResult::Error(EINVAL); + } + + auto readeriterator = FsReaderIterator::Constructor(); + if (!readeriterator.IsSuccess()) { + HILOGE("Failed to instantiate class ReaderIterator"); + return FsResult::Error(UNKNOWN_ERR); + } + + auto readerIteratorEntity = readeriterator.GetData().value()->GetReaderIteratorEntity(); + if (!readerIteratorEntity) { + HILOGE("Failed to get readerIteratorEntity"); + return FsResult::Error(UNKNOWN_ERR); + } + readerIteratorEntity->iterator = iterator; + readerIteratorEntity->offset = offset; + return FsResult::Success(readeriterator.GetData().value()); +} + +FsResult ReadLinesCore::DoReadLines(const string &path, optional option) +{ + if (option.has_value()) { + int ret = CheckOptionArg(option); + if (ret) { + HILOGE("Invalid option.encoding parameter"); + return FsResult::Error(ret); + } + } + + auto iterator = ::ReaderIterator(path.c_str()); + if (iterator == nullptr) { + HILOGE("Failed to read lines of the file, error: %{public}d", errno); + return FsResult::Error(errno); + } + + int64_t offset = 0; + int ret = GetFileSize(path, offset); + if (ret != 0) { + HILOGE("Failed to get size of the file"); + return FsResult::Error(ret); + } + auto readeriterator = InstantiateReaderIterator(iterator, offset); + if (!readeriterator.IsSuccess()) { + return FsResult::Error(ENOMEM); + } + return FsResult::Success(readeriterator.GetData().value()); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_lines_core.h b/interfaces/kits/js/src/mod_fs/properties/read_lines_core.h new file mode 100644 index 0000000000000000000000000000000000000000..a450cc43188f2765786fde02ed8a2c8d07166ae9 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_lines_core.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 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_READ_LINES_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_LINES_CORE_H + +#include + +#include "filemgmt_libfs.h" +#include "fs_reader_iterator.h" +#include "fs_utils.h" +#include "readeriterator_entity.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +struct Options final { + std::string encoding; +}; + +class ReadLinesCore final { +public: + static FsResult DoReadLines( + const std::string &path, std::optional option = std::nullopt); +}; + +const std::string PROCEDURE_READLINES_NAME = "FileIOReadLines"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_LINES_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_text_core.cpp b/interfaces/kits/js/src/mod_fs/properties/read_text_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..90b1b71095eca8e106dad4fa14cd74ac48a44d30 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_text_core.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025 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 "read_text_core.h" + +#include +#include +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static tuple> ValidReadTextArg( + const std::optional &options) +{ + int64_t offset = -1; + int64_t len = 0; + bool hasLen = false; + unique_ptr encoding { new char[]{ "utf-8" } }; + + if (!options.has_value()) { + return { true, offset, hasLen, len, move(encoding) }; + } + + ReadTextOptions op = options.value(); + if (op.offset.has_value()) { + offset = op.offset.value(); + if (offset < 0) { + HILOGE("Illegal option.offset parameter"); + return { false, offset, hasLen, len, nullptr }; + } + } + + if (op.length.has_value()) { + len = op.length.value(); + if (len < 0 || len > UINT_MAX) { + HILOGE("Illegal option.length parameter"); + return { false, offset, hasLen, len, nullptr }; + } + hasLen = true; + } + + if (op.encoding.has_value()) { + auto encoding = op.encoding.value(); + if (encoding != "utf-8") { + HILOGE("Illegal option.encoding parameter"); + return { false, offset, hasLen, len, nullptr }; + } + } + + return { true, offset, hasLen, len, move(encoding) }; +} + +static int OpenFile(const std::string& path) +{ + std::unique_ptr openReq = { + new uv_fs_t, FsUtils::FsReqCleanup + }; + if (openReq == nullptr) { + HILOGE("Failed to request heap memory."); + return -ENOMEM; + } + + return uv_fs_open(nullptr, openReq.get(), path.c_str(), O_RDONLY, + S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr); +} + +static int ReadFromFile(int fd, int64_t offset, string& buffer) +{ + uv_buf_t readbuf = uv_buf_init(const_cast(buffer.c_str()), static_cast(buffer.size())); + std::unique_ptr readReq = { + new uv_fs_t, FsUtils::FsReqCleanup }; + if (readReq == nullptr) { + HILOGE("Failed to request heap memory."); + return -ENOMEM; + } + return uv_fs_read(nullptr, readReq.get(), fd, &readbuf, 1, offset, nullptr); +} + +FsResult> ReadTextCore::DoReadText(const std::string &path, + const std::optional &options) +{ + auto [resGetReadTextArg, offset, hasLen, len, encoding] = ValidReadTextArg(options); + if (!resGetReadTextArg) { + return FsResult>::Error(EINVAL); + } + + OHOS::DistributedFS::FDGuard sfd; + int fd = OpenFile(path); + if (fd < 0) { + HILOGD("Failed to open file by ret: %{public}d", fd); + return FsResult>::Error(fd); + } + sfd.SetFD(fd); + + struct stat statbf; + if ((!sfd) || (fstat(sfd.GetFD(), &statbf) < 0)) { + HILOGE("Failed to get stat of file by fd: %{public}d", sfd.GetFD()); + return FsResult>::Error(errno); + } + + if (offset > statbf.st_size) { + HILOGE("Invalid offset: %{public}" PRIu64, offset); + return FsResult>::Error(EINVAL); + } + + len = (!hasLen || len > statbf.st_size) ? statbf.st_size : len; + string buffer(len, '\0'); + int readRet = ReadFromFile(sfd.GetFD(), offset, buffer); + if (readRet < 0) { + HILOGE("Failed to read file by fd: %{public}d", fd); + return FsResult>::Error(readRet); + } + + return FsResult>::Success(make_tuple(move(buffer), readRet)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/read_text_core.h b/interfaces/kits/js/src/mod_fs/properties/read_text_core.h new file mode 100644 index 0000000000000000000000000000000000000000..87e0a4300d0454472089ce84a70c46ea7573a011 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/read_text_core.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2025 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_READ_TEXT_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_TEXT_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct ReadTextOptions final { + optional offset = nullopt; + optional length = nullopt; + optional encoding = nullopt; +}; + +class ReadTextCore final { +public: + static FsResult> DoReadText(const string &filePath, + const optional &options = nullopt); +}; + +const string PROCEDURE_READTEXT_NAME = "FileIOReadText"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_READ_TEXT_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/rename_core.cpp b/interfaces/kits/js/src/mod_fs/properties/rename_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1edff30a2084d8e8f6387358103de195ac7aa3fa --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/rename_core.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 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 "rename_core.h" + +#include +#include +#include + +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult RenameCore::DoRename(const string &src, const string &dest) +{ + std::unique_ptr renameReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!renameReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_rename(nullptr, renameReq.get(), src.c_str(), dest.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to rename file with path"); + return FsResult::Error(ret); + } + return FsResult::Success(); +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/rename_core.h b/interfaces/kits/js/src/mod_fs/properties/rename_core.h new file mode 100644 index 0000000000000000000000000000000000000000..0eded116821e7c3a62b1dc216146c47438e2ba13 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/rename_core.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_RENAME_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_RENAME_CORE_H + +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +class RenameCore { +public: + static FsResult DoRename(const string &src, const string &dest); +}; + +const string PROCEDURE_RENAME_NAME = "FileIORename"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_RENAME_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/rmdir_core.cpp b/interfaces/kits/js/src/mod_fs/properties/rmdir_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c87ce49efe9c9101f16f62ed00f58c048517a49a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/rmdir_core.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025 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 "rmdir_core.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +#ifdef __MUSL__ +static int32_t RmDirent(const string &fpath) +{ + std::filesystem::path strToPath(fpath); + std::error_code errCode; + std::uintmax_t num = std::filesystem::remove_all(strToPath, errCode); + if (errCode.value() != ERRNO_NOERR) { + HILOGD("Failed to remove directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + if (!num || std::filesystem::exists(strToPath, errCode)) { + HILOGE("Failed to remove directory, dirPath does not exist"); + return ENOENT; + } + if (errCode.value() != ERRNO_NOERR) { + HILOGE("fs exists fail, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +#else +static int32_t RmDirent(const string &fpath) +{ + std::unique_ptr scandir_req = { + new (std::nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (!scandir_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = 0; + ret = uv_fs_scandir(nullptr, scandir_req.get(), fpath.c_str(), 0, nullptr); + if (ret < 0) { + HILOGE("Failed to scandir, ret: %{public}d", ret); + return ret; + } + uv_dirent_t dent; + while (uv_fs_scandir_next(scandir_req.get(), &dent) != UV_EOF) { + string filePath = fpath + "/" + string(dent.name); + if (dent.type == UV_DIRENT_FILE) { + std::unique_ptr unlink_req = { + new (std::nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (!unlink_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + ret = uv_fs_unlink(nullptr, unlink_req.get(), filePath.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to unlink file, ret: %{public}d", ret); + return ret; + } + } else if (dent.type == UV_DIRENT_DIR) { + auto rmDirentRes = RmDirent(filePath); + if (rmDirentRes) { + return rmDirentRes; + } + } + } + std::unique_ptr rmdir_req = { + new (std::nothrow) uv_fs_t, FsUtils::FsReqCleanup}; + if (!rmdir_req) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + ret = uv_fs_rmdir(nullptr, rmdir_req.get(), fpath.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to rmdir empty dir, ret: %{public}d", ret); + return ret; + } + return ERRNO_NOERR; +} +#endif + +FsResult RmdirentCore::DoRmdirent(const string &fpath) +{ + if (fpath.empty()) { + HILOGE("Invalid path"); + return FsResult::Error(EINVAL); + } + + auto err = RmDirent(fpath); + if (err) { + return FsResult::Error(err); + } + return FsResult::Success(); +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/rmdir_core.h b/interfaces/kits/js/src/mod_fs/properties/rmdir_core.h new file mode 100644 index 0000000000000000000000000000000000000000..90a6902fa586d24413015e6dadd864abdfe8d5ea --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/rmdir_core.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2025 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_RMDIR_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_RMDIR_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class RmdirentCore final { +public: + static FsResult DoRmdirent(const std::string &fpath); +}; +const std::string PROCEDURE_RMDIRENT_NAME = "FileIORmDirent"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_RMDIR_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/stat_core.cpp b/interfaces/kits/js/src/mod_fs/properties/stat_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71a2fb62cba4b2364ef126ae701ec6808362d23b --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/stat_core.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2025 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 "stat_core.h" + +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" +#include "fs_stat_entity.h" +#include "stat_instantiator.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static bool IsPath(const FileInfo &fileInfo) +{ + auto path = fileInfo.path.get(); + if (path == nullptr || strlen(path) == 0) { + return false; + } + return true; +} + +static tuple IsFd(const FileInfo &fileInfo) +{ + auto fdg = fileInfo.fdg.get(); + if (fdg == nullptr) { + return make_tuple(false, 0); + } + return make_tuple(true, fdg->GetFD()); +} + +static tuple ValidFileInfo(const FileInfo &fileInfo) +{ + auto isPath = IsPath(fileInfo); + if (isPath) { + auto &path = const_cast &>(fileInfo.path); + return { true, FileInfo { true, move(path), {} } }; + } + auto [isFd, fd] = IsFd(fileInfo); + if (isFd) { + if (fd < 0) { + HILOGE("Invalid fd"); + return { false, FileInfo { false, {}, {} } }; + } + auto fdg = CreateUniquePtr(fd, false); + if (fdg == nullptr) { + HILOGE("Failed to request heap memory."); + return { false, FileInfo { false, {}, {} } }; + } + return { true, FileInfo { false, {}, move(fdg) } }; + } + HILOGE("Invalid parameter"); + return { false, FileInfo { false, {}, {} } }; +}; + +static int32_t CheckFsStat(const FileInfo &fileInfo, uv_fs_t *req) +{ + if (fileInfo.isPath) { + int ret = uv_fs_stat(nullptr, req, fileInfo.path.get(), nullptr); + if (ret < 0) { + HILOGD("Failed to stat file with path, ret is %{public}d", ret); + return ret; + } + } else { + int ret = uv_fs_fstat(nullptr, req, fileInfo.fdg->GetFD(), nullptr); + if (ret < 0) { + HILOGE("Failed to stat file with fd, ret is %{public}d", ret); + return ret; + } + } + return ERRNO_NOERR; +} + +FsResult StatCore::DoStat(const FileInfo &fileinfo) +{ + auto [succ, info] = ValidFileInfo(fileinfo); + if (!succ) { + return FsResult::Error(EINVAL); + } + + std::unique_ptr stat_req = { new (std::nothrow) uv_fs_t, + FsUtils::FsReqCleanup }; + if (!stat_req) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + auto err = CheckFsStat(info, stat_req.get()); + if (err) { + return FsResult::Error(err); + } + +#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) + auto arg = CreateSharedPtr(move(info)); + if (arg == nullptr) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + auto stat = StatInstantiator::InstantiateStat(stat_req->statbuf, arg); +#else + auto stat = StatInstantiator::InstantiateStat(stat_req->statbuf); +#endif + if (stat == nullptr) { + return FsResult::Error(ENOMEM); + } + return FsResult::Success(stat); +} + +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/stat_core.h b/interfaces/kits/js/src/mod_fs/properties/stat_core.h new file mode 100644 index 0000000000000000000000000000000000000000..88cc5ab96614faa196b9a6ca901a8749ad9be996 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/stat_core.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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_STAT_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_STAT_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_stat.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { +class StatCore final { +public: + static FsResult DoStat(const FileInfo &fileinfo); +}; +const std::string PROCEDURE_STAT_NAME = "FileIOStat"; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_STAT_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/symlink_core.cpp b/interfaces/kits/js/src/mod_fs/properties/symlink_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c447187189726243a8583d8c78502ba800705d53 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/symlink_core.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 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 "symlink_core.h" + +#include +#include +#include +#include + +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult SymlinkCore::DoSymlink(const string &target, const string &srcPath) +{ + std::unique_ptr symlinkReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!symlinkReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_symlink(nullptr, symlinkReq.get(), srcPath.c_str(), target.c_str(), 0, nullptr); + if (ret < 0) { + HILOGE("Failed to create a link for old path"); + return FsResult::Error(ret); + } + return FsResult::Success(); +} +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/symlink_core.h b/interfaces/kits/js/src/mod_fs/properties/symlink_core.h new file mode 100644 index 0000000000000000000000000000000000000000..223c8b683d30b409e5c9882386d0e92632c64741 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/symlink_core.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 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_SYMLINK_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_SYMLINK_CORE_H + +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class SymlinkCore final { +public: + static FsResult DoSymlink(const string &target, const string &srcPath); +}; +const std::string PROCEDURE_RMDIRENT_NAME = "FileIOSymLink"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_SYMLINK_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/truncate_core.cpp b/interfaces/kits/js/src/mod_fs/properties/truncate_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..66b68f185be7c5dfa419e1028db09190e175003c --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/truncate_core.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025 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 "truncate_core.h" + +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static bool ValidFileInfo(FileInfo &fileInfo) +{ + if (!fileInfo.isPath) { + auto fd = fileInfo.fdg->GetFD(); + if (fd < 0) { + HILOGE("Invalid fd"); + return false; + } + } + return true; +} + +static int Truncate(FileInfo &fileInfo, int64_t truncateLen) +{ + if (fileInfo.isPath) { + std::unique_ptr openReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!openReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_open( + nullptr, openReq.get(), fileInfo.path.get(), O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, nullptr); + if (ret < 0) { + return ret; + } + std::unique_ptr ftruncateReq = { new uv_fs_t, + FsUtils::FsReqCleanup }; + if (!ftruncateReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + ret = uv_fs_ftruncate(nullptr, ftruncateReq.get(), ret, truncateLen, nullptr); + if (ret < 0) { + HILOGE("Failed to truncate file by path"); + return ret; + } + } else { + std::unique_ptr ftruncateReq = { new uv_fs_t, + FsUtils::FsReqCleanup }; + if (!ftruncateReq) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int ret = uv_fs_ftruncate(nullptr, ftruncateReq.get(), fileInfo.fdg->GetFD(), truncateLen, nullptr); + if (ret < 0) { + HILOGE("Failed to truncate file by fd for libuv error %{public}d", ret); + return ret; + } + } + return ERRNO_NOERR; +} + +FsResult TruncateCore::DoTruncate(FileInfo &fileInfo, const std::optional &len) + +{ + auto succ = ValidFileInfo(fileInfo); + if (!succ) { + return FsResult::Error(EINVAL); + } + + int64_t truncateLen = 0; + if (len.has_value()) { + truncateLen = len.value(); + if (truncateLen < 0) { + HILOGE("Invalid truncate length"); + return FsResult::Error(EINVAL); + } + } + + auto err = Truncate(fileInfo, truncateLen); + if (err) { + return FsResult::Error(err); + } + + return FsResult::Success(); +} +} // namespace OHOS::FileManagement::ModuleFileIO \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/truncate_core.h b/interfaces/kits/js/src/mod_fs/properties/truncate_core.h new file mode 100644 index 0000000000000000000000000000000000000000..a717d35c3e58ed135a4d7e252eccaa3da63dad73 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/truncate_core.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025 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_TRUNCATE_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_TRUNCATE_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS::FileManagement::ModuleFileIO { + +class TruncateCore final { +public: + static FsResult DoTruncate(FileInfo &fileInfo, const std::optional &len = std::nullopt); +}; +const std::string PROCEDURE_TRUNCATE_NAME = "FileIOTruncate"; +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_TRUNCATE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/unlink_core.cpp b/interfaces/kits/js/src/mod_fs/properties/unlink_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ecb92452e2eeb401b856238f52175487ae824523 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/unlink_core.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 "unlink_core.h" + +#ifdef FILE_API_TRACE +#include "hitrace_meter.h" +#endif + +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult UnlinkCore::DoUnlink(const std::string &src) +{ + std::unique_ptr unlink_req = { + new uv_fs_t, FsUtils::FsReqCleanup }; + if (!unlink_req) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_unlink(nullptr, unlink_req.get(), src.c_str(), nullptr); + if (ret < 0) { + HILOGD("Failed to unlink with path"); + return FsResult::Error(ret); + } + + return FsResult::Success(); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/unlink_core.h b/interfaces/kits/js/src/mod_fs/properties/unlink_core.h new file mode 100755 index 0000000000000000000000000000000000000000..b2ea553f4b62130bc691bda5daca16dbe7bc28d4 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/unlink_core.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 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_UNLINK_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_UNLINK_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class UnlinkCore final { +public: + static FsResult DoUnlink(const std::string &src); +}; +const std::string PROCEDURE_READTEXT_NAME = "FileIOUnlink"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_UNLINK_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/utimes_core.cpp b/interfaces/kits/js/src/mod_fs/properties/utimes_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4b517167bf69d8fbbee4b590ba089d193c6c7746 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/utimes_core.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 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 "utimes_core.h" + +#include + +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult UtimesCore::DoUtimes(const string &path, const double mtime) +{ + if (mtime < 0) { + HILOGE("Invalid mtime"); + return FsResult::Error(EINVAL); + } + std::unique_ptr statReq = { + new (std::nothrow) uv_fs_t, FsUtils::FsReqCleanup }; + if (!statReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_stat(nullptr, statReq.get(), path.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to get stat of the file by path"); + return FsResult::Error(ret); + } + + std::unique_ptr utimesReq = { + new uv_fs_t, FsUtils::FsReqCleanup }; + if (!utimesReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + + double atime = static_cast(statReq->statbuf.st_atim.tv_sec) + + static_cast(statReq->statbuf.st_atim.tv_nsec) / NS; + ret = uv_fs_utime(nullptr, utimesReq.get(), path.c_str(), atime, mtime / MS, nullptr); + if (ret < 0) { + HILOGE("Failed to chang mtime of the file for %{public}d", ret); + return FsResult::Error(ret); + } + return FsResult::Success(); +} +} // ModuleFileIO +} // FileManagement +} // OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/utimes_core.h b/interfaces/kits/js/src/mod_fs/properties/utimes_core.h new file mode 100644 index 0000000000000000000000000000000000000000..86fe8c4fd83dded66c52ddf571c158e1799330a6 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/utimes_core.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 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_UTIMES_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_UTIMES_CORE_H + +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +class UtimesCore final { +public: + static FsResult DoUtimes(const string &path, const double mtime); +}; +const std::string PROCEDURE_RMDIRENT_NAME = "FileIOUtimes"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_UTIMES_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/write_core.cpp b/interfaces/kits/js/src/mod_fs/properties/write_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f8498fabcbbe50da8778f9864de9334f23657f75 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/write_core.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025 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 "write_core.h" + +#include +#include +#include +#include +#include +#include + +#ifdef FILE_API_TRACE +#include "hitrace_meter.h" +#endif + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static tuple ValidWriteArg( + void *buffer, const size_t bufLen, const optional &options) +{ + size_t retLen = 0; + int64_t offset = -1; + bool succ = false; + + if (bufLen > UINT_MAX) { + HILOGE("The Size of buffer is too large"); + return { false, nullptr, 0, offset }; + } + + optional lengthOp = nullopt; + optional offsetOp = nullopt; + if (options.has_value()) { + WriteOptions op = options.value(); + lengthOp = op.length; + offsetOp = op.offset; + } + + tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp); + if (!succ) { + HILOGE("Failed to get actual length"); + return { false, nullptr, 0, offset }; + } + + if (offsetOp.has_value()) { + offset = offsetOp.value(); + if (offset < 0) { + HILOGE("option.offset shall be positive number"); + return { false, nullptr, 0, offset }; + } + } + return { true, buffer, retLen, offset }; +} + +FsResult WriteCore::DoWrite(const int32_t fd, const string &buffer, const optional &options) +{ + if (fd < 0) { + HILOGE("Invalid fd"); + return FsResult::Error(EINVAL); + } + + bool succ = false; + size_t len = 0; + int64_t offset = -1; + void *buf = const_cast(static_cast(buffer.c_str())); + size_t bufLen = static_cast(buffer.length()); + + tie(succ, buf, len, offset) = ValidWriteArg(buf, bufLen, options); + if (!succ) { + HILOGE("Failed to resolve buf and options"); + return FsResult::Error(EINVAL); + } + + return DoWrite(fd, buf, len, offset); +} + +FsResult WriteCore::DoWrite(const int32_t fd, const ArrayBuffer &buffer, const optional &options) +{ + if (fd < 0) { + HILOGE("Invalid fd"); + return FsResult::Error(EINVAL); + } + + bool succ = false; + size_t len = 0; + int64_t offset = -1; + void *buf = nullptr; + + tie(succ, buf, len, offset) = ValidWriteArg(buffer.buf, buffer.length, options); + if (!succ) { + HILOGE("Failed to resolve buf and options"); + return FsResult::Error(EINVAL); + } + + return DoWrite(fd, buf, len, offset); +} + +FsResult WriteCore::DoWrite(const int32_t fd, void *buf, const size_t len, const int64_t offset) +{ + uv_buf_t buffer = uv_buf_init(static_cast(buf), static_cast(len)); + unique_ptr write_req = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!write_req) { + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_write(nullptr, write_req.get(), fd, &buffer, 1, offset, nullptr); + if (ret < 0) { + HILOGE("Failed to write file for %{public}d", ret); + return FsResult::Error(ret); + } + return FsResult::Success(static_cast(ret)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/write_core.h b/interfaces/kits/js/src/mod_fs/properties/write_core.h new file mode 100644 index 0000000000000000000000000000000000000000..5d4d2192be0a740a16a89ee1213f5db1d448dd02 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/write_core.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2025 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_WRITE_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_WRITE_CORE_H + +#include "filemgmt_libfs.h" +#include "filemgmt_libhilog.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +struct WriteOptions { + optional length = nullopt; + optional offset = nullopt; + optional encoding = nullopt; +}; + +class WriteCore final { +public: + static FsResult DoWrite( + const int32_t fd, const string &buffer, const optional &options = nullopt); + static FsResult DoWrite( + const int32_t fd, const ArrayBuffer &buffer, const optional &options = nullopt); + +private: + static FsResult DoWrite(const int32_t fd, void *buf, const size_t len, const int64_t offset); +}; + +const string PROCEDURE_WRITE_NAME = "FileIOWrite"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_WRITE_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/xattr_core.cpp b/interfaces/kits/js/src/mod_fs/properties/xattr_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ba22e42c7a4c80b9efda1ace164541f35819eff5 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/xattr_core.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 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 "xattr_core.h" + +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +constexpr size_t MAX_XATTR_SIZE = 4096; + +static bool IsIllegalXattr(const char *key, const char *value) +{ + bool isIllegalKey = strnlen(key, MAX_XATTR_SIZE + 1) > MAX_XATTR_SIZE; + if (isIllegalKey) { + HILOGE("key is too long"); + } + bool isIllegalValue = strnlen(value, MAX_XATTR_SIZE + 1) > MAX_XATTR_SIZE; + if (isIllegalValue) { + HILOGE("value is too long"); + } + return isIllegalKey || isIllegalValue; +} + +static int32_t GetXattrCore(const char *path, const char *key, std::shared_ptr result) +{ + ssize_t xAttrSize = getxattr(path, key, nullptr, 0); + if (xAttrSize == -1 || xAttrSize == 0) { + *result = ""; + return ERRNO_NOERR; + } + auto xattrValue = CreateUniquePtr(static_cast(xAttrSize) + 1); + xAttrSize = getxattr(path, key, xattrValue.get(), static_cast(xAttrSize)); + if (xAttrSize == -1) { + return errno; + } + xattrValue[xAttrSize] = '\0'; + *result = std::string(xattrValue.get()); + return ERRNO_NOERR; +} + +FsResult XattrCore::DoSetXattr(const string &path, const string &key, const string &value) +{ + if (IsIllegalXattr(key.c_str(), value.c_str())) { + HILOGE("Invalid xattr value"); + return FsResult::Error(EINVAL); + } + if (setxattr(path.c_str(), key.c_str(), value.c_str(), strnlen(value.c_str(), MAX_XATTR_SIZE), 0) < 0) { + HILOGE("setxattr fail, errno is %{public}d", errno); + return FsResult::Error(errno); + } + return FsResult::Success(); +} + +FsResult XattrCore::DoGetXattr(const string &path, const string &key) +{ + auto result = make_shared(); + int32_t ret = GetXattrCore(path.c_str(), key.c_str(), result); + if (ret != ERRNO_NOERR) { + HILOGE("Invalid getxattr"); + return FsResult::Error(ret); + } + return FsResult::Success(move(*result)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/xattr_core.h b/interfaces/kits/js/src/mod_fs/properties/xattr_core.h new file mode 100644 index 0000000000000000000000000000000000000000..71ca376e91e7ff8b649fcbc4f6ad327f0b8a7bf2 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/xattr_core.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2025 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_XATTR_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_XATTR_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; +class XattrCore final { +public: + static FsResult DoSetXattr(const string &path, const string &key, const string &value); + static FsResult DoGetXattr(const string &path, const string &key); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_XATTR_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_hash/ani/bind_function_class.cpp b/interfaces/kits/js/src/mod_hash/ani/bind_function_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d93492ac71a06f730371028b6bbe0f76f5a01e55 --- /dev/null +++ b/interfaces/kits/js/src/mod_hash/ani/bind_function_class.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 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 +#include "bind_function.h" +#include "hash_ani.h" + +using namespace OHOS::FileManagement::ModuleFileIO::ANI; + +static ani_status BindStaticMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/hash/HashImpl;"; + std::array methods = { + ani_native_function { "hashSync", "Lstd/core/String;Lstd/core/String;:Lstd/core/String;", + reinterpret_cast(HashAni::HashSync) }, + }; + return BindClass(env, className, methods); +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + if (vm == nullptr) { + HILOGE("Invalid parameter vm"); + return ANI_INVALID_ARGS; + } + + if (result == nullptr) { + HILOGE("Invalid parameter result"); + return ANI_INVALID_ARGS; + } + + ani_env *env; + ani_status status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + HILOGE("Invalid ani version!"); + return ANI_INVALID_VERSION; + } + + status = BindStaticMethods(env); + if (status != ANI_OK) { + HILOGE("Cannot bind native static methods for hash!"); + return status; + }; + + *result = ANI_VERSION_1; + return ANI_OK; +} diff --git a/interfaces/kits/js/src/mod_hash/ani/ets/@ohos.file.hash.ets b/interfaces/kits/js/src/mod_hash/ani/ets/@ohos.file.hash.ets new file mode 100644 index 0000000000000000000000000000000000000000..3c4fd40dcd7028c67d7ef84e3438cda5a921514c --- /dev/null +++ b/interfaces/kits/js/src/mod_hash/ani/ets/@ohos.file.hash.ets @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2025 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. + */ + +import { BusinessError, AsyncCallback } from '@ohos.base'; +import stream from '@ohos.util.stream'; + +export default namespace hash { + export function hash(path: string, algorithm: string): Promise { + return new Promise((resolve: (result: string) => void, reject: (e: BusinessError) => void) => { + let promise = taskpool.execute(HashImpl.hashSync, path, algorithm); + promise.then((ret: NullishType): void => { + let res = ret as string; + resolve(res); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); + } + + export function hash(path: string, algorithm: string, callback: AsyncCallback): void { + let promise = taskpool.execute(HashImpl.hashSync, path, algorithm); + promise.then((ret: NullishType) => { + let e = new BusinessError(); + e.code = 0; + let res = ret as string; + callback(e, res); + }).catch((e: BusinessError): void => { + callback(e, ""); + }); + } + + export function createHash(algorithm: string): HashStream { + return new HashStream(algorithm); + } + + export class HashStream extends stream.Transform { + hs: hash.HashStream; + hashBuf?: ArrayBuffer; + + constructor(algorithm: string) { + super(); + this.hs = new hash.HashStream(algorithm); + } + + digest(): string { + return this.hs.digest(); + } + + update(data: ArrayBuffer): void { + this.hs.update(data); + } + + doTransform(chunk: string, encoding: string, callback: () => void): void { + let charCodes: number[] = []; + for (let i = 0; i < chunk.length; i++) { + charCodes = [...charCodes, chunk.charCodeAt(i)]; + } + const buf = new Uint8Array(charCodes).buffer; + this.hs.update((buf as ArrayBuffer)); + this.push(chunk); + callback(); + } + + doWrite(chunk: string | Uint8Array, encoding: string, callback: () => void): void { + callback(); + } + + doFlush(callback: () => void): void { + callback(); + } + } +} + +class HashImpl { + + static { + loadLibrary("ani_hash_class"); + } + + static native hashSync(path: string, algorithm: string): string; +} diff --git a/interfaces/kits/js/src/mod_hash/ani/hash_ani.cpp b/interfaces/kits/js/src/mod_hash/ani/hash_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6acb4389cdaba7a384403d9e61541fbe9dd6e214 --- /dev/null +++ b/interfaces/kits/js/src/mod_hash/ani/hash_ani.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2025 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 "hash_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "hash_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; + +ani_string HashAni::HashSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string algorithm) +{ + auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto [succAlg, algType] = TypeConverter::ToUTF8String(env, algorithm); + if (!succAlg) { + HILOGE("Invalid algorithm"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = HashCore::DoHash(srcPath, algType); + if (!ret.IsSuccess()) { + HILOGE("DoHash failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const auto &res = ret.GetData().value(); + auto [succ, result] = TypeConverter::ToAniString(env, res); + if (!succ) { + HILOGE("Convert hash value to ani string failed"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_hash/ani/hash_ani.h b/interfaces/kits/js/src/mod_hash/ani/hash_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..7b0890fe78e7ad5dbf86a84553300d1736a5d775 --- /dev/null +++ b/interfaces/kits/js/src/mod_hash/ani/hash_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 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_HASH_PROPERTIES_HASH_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_HASH_PROPERTIES_HASH_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class HashAni final { +public: + static ani_string HashSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string algorithm); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_HASH_PROPERTIES_HASH_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_hash/hash_core.cpp b/interfaces/kits/js/src/mod_hash/hash_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ed75b4b0cd462c8fef0bc8d76009e7bc32d0fd93 --- /dev/null +++ b/interfaces/kits/js/src/mod_hash/hash_core.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 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 "hash_core.h" + +#include +#include +#include + +#include "filemgmt_libhilog.h" +#include "hash_file.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static HASH_ALGORITHM_TYPE GetHashAlgorithm(const string &alg) +{ + return (algorithmMaps.find(alg) != algorithmMaps.end()) ? algorithmMaps.at(alg) : HASH_ALGORITHM_TYPE_UNSUPPORTED; +} + +FsResult HashCore::DoHash(const string &path, const string &algorithm) +{ + HASH_ALGORITHM_TYPE algType = GetHashAlgorithm(algorithm); + if (algType == HASH_ALGORITHM_TYPE_UNSUPPORTED) { + HILOGE("Invalid algoritm"); + return FsResult::Error(EINVAL); + } + + int ret = EIO; + auto arg = make_shared(); + string &res = *arg; + if (algType == HASH_ALGORITHM_TYPE_MD5) { + tie(ret, res) = DistributedFS::HashFile::HashWithMD5(path); + } else if (algType == HASH_ALGORITHM_TYPE_SHA1) { + tie(ret, res) = DistributedFS::HashFile::HashWithSHA1(path); + } else if (algType == HASH_ALGORITHM_TYPE_SHA256) { + tie(ret, res) = DistributedFS::HashFile::HashWithSHA256(path); + } + + if (ret) { + return FsResult::Error(ret); + } + + return FsResult::Success(*arg); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_hash/hash_core.h b/interfaces/kits/js/src/mod_hash/hash_core.h new file mode 100644 index 0000000000000000000000000000000000000000..47119f1ac3e43d512c900cd81b3e8dc2f35e49c0 --- /dev/null +++ b/interfaces/kits/js/src/mod_hash/hash_core.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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_HASH_PROPERTIES_HASH_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_HASH_PROPERTIES_HASH_CORE_H + +#include +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +enum HASH_ALGORITHM_TYPE { + HASH_ALGORITHM_TYPE_MD5, + HASH_ALGORITHM_TYPE_SHA1, + HASH_ALGORITHM_TYPE_SHA256, + HASH_ALGORITHM_TYPE_UNSUPPORTED, +}; + +const std::map algorithmMaps = { + {"md5", HASH_ALGORITHM_TYPE_MD5}, + {"sha1", HASH_ALGORITHM_TYPE_SHA1}, + {"sha256", HASH_ALGORITHM_TYPE_SHA256}, +}; + +class HashCore final { +public: + static FsResult DoHash(const std::string &path, const std::string &algorithm); +}; + +const std::string PROCEDURE_HASH_NAME = "FileIOHash"; +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_HASH_PROPERTIES_HASH_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_securitylabel/ani/bind_function_class.cpp b/interfaces/kits/js/src/mod_securitylabel/ani/bind_function_class.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5bb0f2650cfb3291dd34e0fce1f212a4d9bc25e7 --- /dev/null +++ b/interfaces/kits/js/src/mod_securitylabel/ani/bind_function_class.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 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 +#include "bind_function.h" +#include "securitylabel_ani.h" + +using namespace OHOS::FileManagement::ModuleFileIO::ANI; + +static ani_status BindStaticMethods(ani_env *env) +{ + static const char *className = "L@ohos/file/securityLabel/SecurityLabelImpl;"; + std::array methods = { + ani_native_function { "setSecurityLabelSync", "Lstd/core/String;Lstd/core/String;:V", + reinterpret_cast(SecurityLabelAni::SetSecurityLabelSync) }, + ani_native_function { "getSecurityLabelSync", "Lstd/core/String;:Lstd/core/String;", + reinterpret_cast(SecurityLabelAni::GetSecurityLabelSync) }, + }; + return BindClass(env, className, methods); +} + +ANI_EXPORT ani_status ANI_Constructor(ani_vm *vm, uint32_t *result) +{ + if (vm == nullptr) { + HILOGE("Invalid parameter vm"); + return ANI_INVALID_ARGS; + } + + if (result == nullptr) { + HILOGE("Invalid parameter result"); + return ANI_INVALID_ARGS; + } + + ani_env *env; + ani_status status = vm->GetEnv(ANI_VERSION_1, &env); + if (status != ANI_OK) { + HILOGE("Invalid ani version!"); + return ANI_INVALID_VERSION; + } + + status = BindStaticMethods(env); + if (status != ANI_OK) { + HILOGE("Cannot bind native static methods for securitylabel!"); + return status; + }; + + *result = ANI_VERSION_1; + return ANI_OK; +} diff --git a/interfaces/kits/js/src/mod_securitylabel/ani/ets/@ohos.file.securityLabel.ets b/interfaces/kits/js/src/mod_securitylabel/ani/ets/@ohos.file.securityLabel.ets new file mode 100644 index 0000000000000000000000000000000000000000..b4268c6118846a602353c671ca9f86575dfea30e --- /dev/null +++ b/interfaces/kits/js/src/mod_securitylabel/ani/ets/@ohos.file.securityLabel.ets @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025 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. + */ + +import { BusinessError, AsyncCallback } from '@ohos.base'; + +namespace securityLabel { + export type DataLevel = 's0' | 's1' | 's2' | 's3' | 's4'; + + export function setSecurityLabel(path: string, type: DataLevel): Promise { + return new Promise((resolve: (result: undefined) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string, type: DataLevel): void => SecurityLabelImpl.setSecurityLabelSync(path, type), path, type); + promise.then((ret: NullishType): void => { + resolve(undefined); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); + } + + export function setSecurityLabel(path: string, type: DataLevel, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string, type: DataLevel): void => SecurityLabelImpl.setSecurityLabelSync(path, type), path, type); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + callback(e, undefined); + }).catch((e: BusinessError): void => { + callback(e, undefined); + }); + } + + export function setSecurityLabelSync(path: string, type: DataLevel): void { + return SecurityLabelImpl.setSecurityLabelSync(path, type); + } + + export function getSecurityLabel(path: string): Promise { + return new Promise((resolve: (result: string) => void, reject: (e: BusinessError) => void): void => { + let promise = taskpool.execute((path: string): string => SecurityLabelImpl.getSecurityLabelSync(path), path); + promise.then((ret: NullishType): void => { + let r = ret as string; + resolve(r); + }).catch((e: BusinessError): void => { + reject(e); + }); + }); + } + + export function getSecurityLabel(path: string, callback: AsyncCallback): void { + let promise = taskpool.execute((path: string): string => SecurityLabelImpl.getSecurityLabelSync(path), path); + promise.then((ret: NullishType): void => { + let e = new BusinessError(); + e.code = 0; + let r = ret as string; + callback(e, r); + }).catch((e: BusinessError): void => { + callback(e, ""); + }); + } + + export function getSecurityLabelSync(path: string): string { + return SecurityLabelImpl.getSecurityLabelSync(path); + } +} + +export default securityLabel; + +class SecurityLabelImpl { + + static { + loadLibrary("ani_securitylabel_class"); + } + + static native setSecurityLabelSync(path: string, type: securityLabel.DataLevel): void; + static native getSecurityLabelSync(path: string): string; +} diff --git a/interfaces/kits/js/src/mod_securitylabel/ani/securitylabel_ani.cpp b/interfaces/kits/js/src/mod_securitylabel/ani/securitylabel_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4d6fd2b3211890d4e1092c8925da40bddbe0269f --- /dev/null +++ b/interfaces/kits/js/src/mod_securitylabel/ani/securitylabel_ani.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2025 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 "securitylabel_ani.h" + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "securitylabel_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +using namespace std; +using namespace OHOS::FileManagement::ModuleFileIO; +using namespace OHOS::FileManagement::ModuleSecurityLabel; + +void SecurityLabelAni::SetSecurityLabelSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string level) +{ + auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [succLevel, dataLevel] = TypeConverter::ToUTF8String(env, level); + if (!succLevel) { + HILOGE("Invalid dataLevel"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto ret = DoSetSecurityLabel(srcPath, dataLevel); + if (!ret.IsSuccess()) { + HILOGE("Set securitylabel failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return; + } +} + +ani_string SecurityLabelAni::GetSecurityLabelSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path) +{ + auto [succPath, srcPath] = TypeConverter::ToUTF8String(env, path); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = DoGetSecurityLabel(srcPath); + if (!ret.IsSuccess()) { + HILOGE("Get securitylabel failed"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + string res = ret.GetData().value(); + auto [succ, result] = TypeConverter::ToAniString(env, res); + if (!succ) { + HILOGE("Create ani_string error"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_securitylabel/ani/securitylabel_ani.h b/interfaces/kits/js/src/mod_securitylabel/ani/securitylabel_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..8bb5741c9c347700ded871b900efc44297c823d9 --- /dev/null +++ b/interfaces/kits/js/src/mod_securitylabel/ani/securitylabel_ani.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 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 SECURITYLABEL_ANI_H +#define SECURITYLABEL_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class SecurityLabelAni final { +public: + static void SetSecurityLabelSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path, ani_string level); + static ani_string GetSecurityLabelSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string path); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // SECURITYLABEL_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_securitylabel/securitylabel_core.cpp b/interfaces/kits/js/src/mod_securitylabel/securitylabel_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d68002e8aa8ddcab3863ebed88d44bcc22d1fa13 --- /dev/null +++ b/interfaces/kits/js/src/mod_securitylabel/securitylabel_core.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 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 "securitylabel_core.h" + +#include "filemgmt_libhilog.h" +#include "security_label.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleSecurityLabel { +using namespace std; +FsResult DoSetSecurityLabel(const string &path, const string &dataLevel) +{ + if (DATA_LEVEL.find(dataLevel) == DATA_LEVEL.end()) { + HILOGE("Invalid Argument of dataLevelEnum"); + return FsResult::Error(EINVAL); + } + + bool ret = SecurityLabel::SetSecurityLabel(path, dataLevel); + if (!ret) { + return FsResult::Error(errno); + } + + return FsResult::Success(); +} + +FsResult DoGetSecurityLabel(const string &path) +{ + string ret = SecurityLabel::GetSecurityLabel(path); + return FsResult::Success(move(ret)); +} + +} // namespace ModuleSecurityLabel +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_securitylabel/securitylabel_core.h b/interfaces/kits/js/src/mod_securitylabel/securitylabel_core.h new file mode 100644 index 0000000000000000000000000000000000000000..cb7766eaf5a6087c1e449e2077046ee4a63a9f33 --- /dev/null +++ b/interfaces/kits/js/src/mod_securitylabel/securitylabel_core.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025 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 SECURITYLABEL_CORE_H +#define SECURITYLABEL_CORE_H + +#include "filemgmt_libfs.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleSecurityLabel { +using namespace ModuleFileIO; + +FsResult DoSetSecurityLabel(const string &path, const string &dataLevel); +FsResult DoGetSecurityLabel(const string &path); + +} // namespace ModuleSecurityLabel +} // namespace FileManagement +} // namespace OHOS +#endif // SECURITYLABEL_CORE_H \ No newline at end of file diff --git a/utils/filemgmt_libfs/BUILD.gn b/utils/filemgmt_libfs/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..eda44fef994ef3bcf2c4894055b4b26c48470137 --- /dev/null +++ b/utils/filemgmt_libfs/BUILD.gn @@ -0,0 +1,72 @@ +# 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. + +import("//build/ohos.gni") +import("//foundation/filemanagement/file_api/file_api.gni") + +config("libfs_public_config") { + visibility = [ ":*" ] + + include_dirs = [ + "include", + "${utils_path}/common/include", + ] +} + +ohos_shared_library("filemgmt_libfs") { + cflags_cc = [ "-std=c++17" ] + if (!use_mingw_win && !use_mac) { + cflags = [ + "-fdata-sections", + "-ffunction-sections", + "-Oz", + ] + cflags_cc += [ + "-fvisibility-inlines-hidden", + "-Oz", + ] + branch_protector_ret = "pac_ret" + sanitize = { + integer_overflow = true + ubsan = true + boundary_sanitize = true + cfi = true + cfi_cross_dso = true + debug = false + } + } + + sources = [ "src/fs_error.cpp" ] + + if (use_mingw_win) { + defines = [ "WIN_PLATFORM" ] + } + if (use_mac) { + defines = [ "IOS_PLATFORM" ] + } + + public_configs = [ ":libfs_public_config" ] + + deps = [ "${utils_path}/filemgmt_libhilog:filemgmt_libhilog" ] + + external_deps = [ + "hilog:libhilog", + "libuv:uv", + ] + + use_exceptions = true + + subsystem_name = "filemanagement" + innerapi_tags = [ "platformsdk" ] + part_name = "file_api" +} diff --git a/utils/filemgmt_libfs/include/filemgmt_libfs.h b/utils/filemgmt_libfs/include/filemgmt_libfs.h new file mode 100644 index 0000000000000000000000000000000000000000..facda9a16481c7367cc1e0e179b4933ac5202837 --- /dev/null +++ b/utils/filemgmt_libfs/include/filemgmt_libfs.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2025 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 FILEMGMT_LIBN_FILEMGMT_LIBFS_H +#define FILEMGMT_LIBN_FILEMGMT_LIBFS_H + +#include "fs_array_buffer.h" +#include "fs_error.h" +#include "fs_result.h" + +#endif // FILEMGMT_LIBN_FILEMGMT_LIBFS_H \ No newline at end of file diff --git a/utils/filemgmt_libfs/include/fs_array_buffer.h b/utils/filemgmt_libfs/include/fs_array_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..52b28a996b7e93c9fd1b2a411330507c0c11c7bc --- /dev/null +++ b/utils/filemgmt_libfs/include/fs_array_buffer.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_FS_ARRAY_BUFFER_H +#define FILEMANAGEMENT_FS_ARRAY_BUFFER_H + +#include + +namespace OHOS::FileManagement::ModuleFileIO { + +struct ArrayBuffer { + void *buf; + size_t length; + + ArrayBuffer(void *buffer, size_t len) : buf(buffer), length(len) {} +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // FILEMANAGEMENT_FS_ARRAY_BUFFER_H \ No newline at end of file diff --git a/utils/filemgmt_libfs/include/fs_error.h b/utils/filemgmt_libfs/include/fs_error.h new file mode 100644 index 0000000000000000000000000000000000000000..94525eec342459861a8b37682b4714ccfad86a6f --- /dev/null +++ b/utils/filemgmt_libfs/include/fs_error.h @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_FS_ERROR_H +#define FILEMANAGEMENT_FS_ERROR_H + +#include +#include +#include +#include +#include + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +#if (defined IOS_PLATFORM) || (defined WIN_PLATFORM) +constexpr int EBADR = 53; +constexpr int EBADFD = 77; +constexpr int ERESTART = 85; +#endif +#ifdef WIN_PLATFORM +constexpr int EDQUOT = 122; +#endif +constexpr int UNKNOWN_ERR = -1; +constexpr int NO_TASK_ERR = -2; +constexpr int CANCEL_ERR = -3; +constexpr int ERRNO_NOERR = 0; +constexpr int ECONNECTIONFAIL = 45; +constexpr int ECONNECTIONABORT = 46; +constexpr int STORAGE_SERVICE_SYS_CAP_TAG = 13600000; +constexpr int FILEIO_SYS_CAP_TAG = 13900000; +constexpr int USER_FILE_MANAGER_SYS_CAP_TAG = 14000000; +constexpr int USER_FILE_SERVICE_SYS_CAP_TAG = 14300000; +constexpr int DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG = 22400000; +constexpr int SOFTBUS_TRANS_FILE_PERMISSION_DENIED = -426114938; +constexpr int SOFTBUS_TRANS_FILE_DISK_QUOTA_EXCEEDED = -426114937; +constexpr int SOFTBUS_TRANS_FILE_NO_MEMORY = -426114936; +constexpr int SOFTBUS_TRANS_FILE_NETWORK_ERROR = -426114935; +constexpr int SOFTBUS_TRANS_FILE_NOT_FOUND = -426114934; +constexpr int SOFTBUS_TRANS_FILE_EXISTED = -426114933; +constexpr int DFS_CANCEL_SUCCESS = 204; +const std::string FILEIO_TAG_ERR_CODE = "code"; +const std::string FILEIO_TAG_ERR_DATA = "data"; + +enum ErrCodeSuffixOfFileIO { + E_PERM = 1, + E_NOENT, + E_SRCH, + E_INTR, + E_IO, + E_NXIO, + E_2BIG, + E_BADF, + E_CHILD, + E_AGAIN, + E_NOMEM, + E_ACCES, + E_FAULT, + E_BUSY, + E_EXIST, + E_XDEV, + E_NODEV, + E_NOTDIR, + E_ISDIR, + E_INVAL, + E_NFILE, + E_MFILE, + E_TXTBSY, + E_FBIG, + E_NOSPC, + E_SPIPE, + E_ROFS, + E_MLINK, + E_DEADLK, + E_NAMETOOLONG, + E_NOSYS, + E_NOTEMPTY, + E_LOOP, + E_WOULDBLOCK, + E_BADR, + E_NOSTR, + E_NODATA, + E_OVERFLOW, + E_BADFD, + E_RESTART, + E_DQUOT, + E_UKERR, + E_NOLCK, + E_NETUNREACH, + E_CONNECTION_FAIL, + E_CONNECTION_ABORT, + E_NOTASK, + E_UNCANCELED, + E_CANCELED, +}; + +enum ErrCodeSuffixOfUserFileManager { + E_DISPLAYNAME = 1, + E_URIM, + E_SUFFIX, + E_TRASH, + E_OPEN_MODE, + E_NOT_ALBUM, + E_ROOT_DIR, + E_MOVE_DENIED, + E_RENAME_DENIED, + E_RELATIVEPATH, + E_INNER_FAIL, + E_FILE_TYPE, + E_FILE_KEY, + E_INPUT +}; + +enum ErrCodeSuffixOfStorageService { + E_IPCSS = 1, + E_NOTSUPPORTEDFS, + E_MOUNT, + E_UNMOUNT, + E_VOLUMESTATE, + E_PREPARE, + E_DELETE, + E_NOOBJECT, + E_OUTOFRANGE +}; + +enum ErrCodeSuffixOfUserFileService { + E_IPCS = 1, + E_URIS, + E_GETINFO, + E_GETRESULT, + E_REGISTER, + E_REMOVE, + E_INIT, + E_NOTIFY, + E_CONNECT, + E_CALLBACK_AND_URI_HAS_NOT_RELATIONS, + E_CALLBACK_IS_NOT_REGISTER, + E_CAN_NOT_FIND_URI, + E_DO_NOT_HAVE_PARENT, + E_LOAD_SA, + E_COUNT +}; + +enum ErrCodeSuffixOfDistributedFile { + E_CLOUD_NOT_READY = 1, + E_NETWORK_ERR, + E_BATTERY_WARNING, + E_EXCEED_MAX_LIMIT, + E_DATABASE_FAILED +}; + +enum CommonErrCode { + E_PERMISSION = 201, + E_PERMISSION_SYS = 202, + E_PARAMS = 401, + E_DEVICENOTSUPPORT = 801, + E_OSNOTSUPPORT = 901, + E_UNKNOWN_ERROR = 13900042 +}; + +static inline std::unordered_map softbusErr2ErrCodeTable { + { SOFTBUS_TRANS_FILE_PERMISSION_DENIED, EPERM }, + { SOFTBUS_TRANS_FILE_DISK_QUOTA_EXCEEDED, EIO }, + { SOFTBUS_TRANS_FILE_NO_MEMORY, ENOMEM }, + { SOFTBUS_TRANS_FILE_NETWORK_ERROR, ENETUNREACH }, + { SOFTBUS_TRANS_FILE_NOT_FOUND, ENOENT }, + { SOFTBUS_TRANS_FILE_EXISTED, EEXIST }, + { DFS_CANCEL_SUCCESS, ECANCELED }, +}; + +static inline std::unordered_map uvCode2ErrCodeTable { + { "EPERM", EPERM }, + { "ENOENT", ENOENT }, + { "ESRCH", ESRCH }, + { "EINTR", EINTR }, + { "EIO", EIO }, + { "ENXIO", ENXIO }, + { "E2BIG", E2BIG }, + { "EBADF", EBADF }, + { "ECHILD", ECHILD }, + { "EAGAIN", EAGAIN }, + { "ENOMEM", ENOMEM }, + { "EACCES", EACCES }, + { "EFAULT", EFAULT }, + { "EBUSY", EBUSY }, + { "EEXIST", EEXIST }, + { "EXDEV", EXDEV }, + { "ENODEV", ENODEV }, + { "ENOTDIR", ENOTDIR }, + { "EISDIR", EISDIR }, + { "EINVAL", EINVAL }, + { "ENFILE", ENFILE }, + { "EMFILE", EMFILE }, + { "ETXTBSY", ETXTBSY }, + { "EFBIG", EFBIG }, + { "ENOSPC", ENOSPC }, + { "ESPIPE", ESPIPE }, + { "EROFS", EROFS }, + { "EMLINK", EMLINK }, + { "EDEADLK", EDEADLK }, + { "ENAMETOOLONG", ENAMETOOLONG }, + { "ENOSYS", ENOSYS }, + { "ENOTEMPTY", ENOTEMPTY }, + { "ELOOP", ELOOP }, + { "EWOULDBLOCK", EWOULDBLOCK }, + { "EBADR", EBADR }, + { "ENOSTR", ENOSTR }, + { "ENODATA", ENODATA }, + { "EOVERFLOW", EOVERFLOW }, + { "EBADFD", EBADFD }, + { "ERESTART", ERESTART }, + { "EDQUOT", EDQUOT }, + { "ENETUNREACH", ENETUNREACH }, + { "ECONNECTIONFAIL", ECONNECTIONFAIL }, + { "ECONNECTIONABORT", ECONNECTIONABORT }, + { "ECANCELED", ECANCELED }, +}; + +static inline std::unordered_map> errCodeTable { + { ERRNO_NOERR, { ERRNO_NOERR, "No error imformation" } }, + { EPERM, { FILEIO_SYS_CAP_TAG + E_PERM, "Operation not permitted" } }, + { ENOENT, { FILEIO_SYS_CAP_TAG + E_NOENT, "No such file or directory" } }, + { ESRCH, { FILEIO_SYS_CAP_TAG + E_SRCH, "No such process" } }, + { EINTR, { FILEIO_SYS_CAP_TAG + E_INTR, "Interrupted system call" } }, + { EIO, { FILEIO_SYS_CAP_TAG + E_IO, "I/O error" } }, + { ENXIO, { FILEIO_SYS_CAP_TAG + E_NXIO, "No such device or address" } }, + { E2BIG, { FILEIO_SYS_CAP_TAG + E_2BIG, "Arg list too long" } }, + { EBADF, { FILEIO_SYS_CAP_TAG + E_BADF, "Bad file descriptor" } }, + { ECHILD, { FILEIO_SYS_CAP_TAG + E_CHILD, "No child processes" } }, + { EAGAIN, { FILEIO_SYS_CAP_TAG + E_AGAIN, "Try again" } }, + { ENOMEM, { FILEIO_SYS_CAP_TAG + E_NOMEM, "Out of memory" } }, + { EACCES, { FILEIO_SYS_CAP_TAG + E_ACCES, "Permission denied" } }, + { EFAULT, { FILEIO_SYS_CAP_TAG + E_FAULT, "Bad address" } }, + { EBUSY, { FILEIO_SYS_CAP_TAG + E_BUSY, "Device or resource busy" } }, + { EEXIST, { FILEIO_SYS_CAP_TAG + E_EXIST, "File exists" } }, + { EXDEV, { FILEIO_SYS_CAP_TAG + E_XDEV, "Cross-device link" } }, + { ENODEV, { FILEIO_SYS_CAP_TAG + E_NODEV, "No such device" } }, + { ENOTDIR, { FILEIO_SYS_CAP_TAG + E_NOTDIR, "Not a directory" } }, + { EISDIR, { FILEIO_SYS_CAP_TAG + E_ISDIR, "Is a directory" } }, + { EINVAL, { FILEIO_SYS_CAP_TAG + E_INVAL, "Invalid argument" } }, + { ENFILE, { FILEIO_SYS_CAP_TAG + E_NFILE, "File table overflow" } }, + { EMFILE, { FILEIO_SYS_CAP_TAG + E_MFILE, "Too many open files" } }, + { ETXTBSY, { FILEIO_SYS_CAP_TAG + E_TXTBSY, "Text file busy" } }, + { EFBIG, { FILEIO_SYS_CAP_TAG + E_FBIG, "File too large" } }, + { ENOSPC, { FILEIO_SYS_CAP_TAG + E_NOSPC, "No space left on device" } }, + { ESPIPE, { FILEIO_SYS_CAP_TAG + E_SPIPE, "Illegal seek" } }, + { EROFS, { FILEIO_SYS_CAP_TAG + E_ROFS, "Read-only file system" } }, + { EMLINK, { FILEIO_SYS_CAP_TAG + E_MLINK, "Too many links" } }, + { EDEADLK, { FILEIO_SYS_CAP_TAG + E_DEADLK, "Resource deadlock would occur" } }, + { ENAMETOOLONG, { FILEIO_SYS_CAP_TAG + E_NAMETOOLONG, "File name too long" } }, + { ENOSYS, { FILEIO_SYS_CAP_TAG + E_NOSYS, "Function not implemented" } }, + { ENOTEMPTY, { FILEIO_SYS_CAP_TAG + E_NOTEMPTY, "Directory not empty" } }, + { ELOOP, { FILEIO_SYS_CAP_TAG + E_LOOP, "Too many symbolic links encountered" } }, + { EWOULDBLOCK, { FILEIO_SYS_CAP_TAG + E_WOULDBLOCK, "Operation would block" } }, + { EBADR, { FILEIO_SYS_CAP_TAG + E_BADR, "Invalid request descriptor" } }, + { ENOSTR, { FILEIO_SYS_CAP_TAG + E_NOSTR, "Device not a stream" } }, + { ENODATA, { FILEIO_SYS_CAP_TAG + E_NODATA, "No data available" } }, + { EOVERFLOW, { FILEIO_SYS_CAP_TAG + E_OVERFLOW, "Value too large for defined data type" } }, + { EBADFD, { FILEIO_SYS_CAP_TAG + E_BADFD, "File descriptor in bad state" } }, + { ERESTART, { FILEIO_SYS_CAP_TAG + E_RESTART, "Interrupted system call should be restarted" } }, + { EDQUOT, { FILEIO_SYS_CAP_TAG + E_DQUOT, "Quota exceeded" } }, + { UNKNOWN_ERR, { FILEIO_SYS_CAP_TAG + E_UKERR, "Unknown error" } }, + { ENOLCK, { FILEIO_SYS_CAP_TAG + E_NOLCK, "No record locks available" } }, + { ENETUNREACH, { FILEIO_SYS_CAP_TAG + E_NETUNREACH, "Network is unreachable" } }, + { ECONNECTIONFAIL, { FILEIO_SYS_CAP_TAG + E_CONNECTION_FAIL, "Connection failed" } }, + { ECONNECTIONABORT, { FILEIO_SYS_CAP_TAG + E_CONNECTION_ABORT, "Software caused connection abort" } }, + { NO_TASK_ERR, { FILEIO_SYS_CAP_TAG + E_NOTASK, "No task can be canceled" } }, + { CANCEL_ERR, { FILEIO_SYS_CAP_TAG + E_UNCANCELED, "Failed to cancel" } }, + { ECANCELED, { FILEIO_SYS_CAP_TAG + E_CANCELED, "Operation canceled" } }, + { FILEIO_SYS_CAP_TAG + E_PERM, { FILEIO_SYS_CAP_TAG + E_PERM, "Operation not permitted" } }, + { FILEIO_SYS_CAP_TAG + E_NOENT, { FILEIO_SYS_CAP_TAG + E_NOENT, "No such file or directory" } }, + { FILEIO_SYS_CAP_TAG + E_SRCH, { FILEIO_SYS_CAP_TAG + E_SRCH, "No such process" } }, + { FILEIO_SYS_CAP_TAG + E_INTR, { FILEIO_SYS_CAP_TAG + E_INTR, "Interrupted system call" } }, + { FILEIO_SYS_CAP_TAG + E_IO, { FILEIO_SYS_CAP_TAG + E_IO, "I/O error" } }, + { FILEIO_SYS_CAP_TAG + E_NXIO, { FILEIO_SYS_CAP_TAG + E_NXIO, "No such device or address" } }, + { FILEIO_SYS_CAP_TAG + E_2BIG, { FILEIO_SYS_CAP_TAG + E_2BIG, "Arg list too long" } }, + { FILEIO_SYS_CAP_TAG + E_BADF, { FILEIO_SYS_CAP_TAG + E_BADF, "Bad file descriptor" } }, + { FILEIO_SYS_CAP_TAG + E_CHILD, { FILEIO_SYS_CAP_TAG + E_CHILD, "No child processes" } }, + { FILEIO_SYS_CAP_TAG + E_AGAIN, { FILEIO_SYS_CAP_TAG + E_AGAIN, "Try again" } }, + { FILEIO_SYS_CAP_TAG + E_NOMEM, { FILEIO_SYS_CAP_TAG + E_NOMEM, "Out of memory" } }, + { FILEIO_SYS_CAP_TAG + E_ACCES, { FILEIO_SYS_CAP_TAG + E_ACCES, "Permission denied" } }, + { FILEIO_SYS_CAP_TAG + E_FAULT, { FILEIO_SYS_CAP_TAG + E_FAULT, "Bad address" } }, + { FILEIO_SYS_CAP_TAG + E_BUSY, { FILEIO_SYS_CAP_TAG + E_BUSY, "Device or resource busy" } }, + { FILEIO_SYS_CAP_TAG + E_EXIST, { FILEIO_SYS_CAP_TAG + E_EXIST, "File exists" } }, + { FILEIO_SYS_CAP_TAG + E_XDEV, { FILEIO_SYS_CAP_TAG + E_XDEV, "Cross-device link" } }, + { FILEIO_SYS_CAP_TAG + E_NODEV, { FILEIO_SYS_CAP_TAG + E_NODEV, "No such device" } }, + { FILEIO_SYS_CAP_TAG + E_NOTDIR, { FILEIO_SYS_CAP_TAG + E_NOTDIR, "Not a directory" } }, + { FILEIO_SYS_CAP_TAG + E_ISDIR, { FILEIO_SYS_CAP_TAG + E_ISDIR, "Is a directory" } }, + { FILEIO_SYS_CAP_TAG + E_INVAL, { FILEIO_SYS_CAP_TAG + E_INVAL, "Invalid argument" } }, + { FILEIO_SYS_CAP_TAG + E_NFILE, { FILEIO_SYS_CAP_TAG + E_NFILE, "File table overflow" } }, + { FILEIO_SYS_CAP_TAG + E_MFILE, { FILEIO_SYS_CAP_TAG + E_MFILE, "Too many open files" } }, + { FILEIO_SYS_CAP_TAG + E_TXTBSY, { FILEIO_SYS_CAP_TAG + E_TXTBSY, "Text file busy" } }, + { FILEIO_SYS_CAP_TAG + E_FBIG, { FILEIO_SYS_CAP_TAG + E_FBIG, "File too large" } }, + { FILEIO_SYS_CAP_TAG + E_NOSPC, { FILEIO_SYS_CAP_TAG + E_NOSPC, "No space left on device" } }, + { FILEIO_SYS_CAP_TAG + E_SPIPE, { FILEIO_SYS_CAP_TAG + E_SPIPE, "Illegal seek" } }, + { FILEIO_SYS_CAP_TAG + E_ROFS, { FILEIO_SYS_CAP_TAG + E_ROFS, "Read-only file system" } }, + { FILEIO_SYS_CAP_TAG + E_MLINK, { FILEIO_SYS_CAP_TAG + E_MLINK, "Too many links" } }, + { FILEIO_SYS_CAP_TAG + E_DEADLK, { FILEIO_SYS_CAP_TAG + E_DEADLK, "Resource deadlock would occur" } }, + { FILEIO_SYS_CAP_TAG + E_NAMETOOLONG, { FILEIO_SYS_CAP_TAG + E_NAMETOOLONG, "File name too long" } }, + { FILEIO_SYS_CAP_TAG + E_NOSYS, { FILEIO_SYS_CAP_TAG + E_NOSYS, "Function not implemented" } }, + { FILEIO_SYS_CAP_TAG + E_NOTEMPTY, { FILEIO_SYS_CAP_TAG + E_NOTEMPTY, "Directory not empty" } }, + { FILEIO_SYS_CAP_TAG + E_LOOP, { FILEIO_SYS_CAP_TAG + E_LOOP, "Too many symbolic links encountered" } }, + { FILEIO_SYS_CAP_TAG + E_WOULDBLOCK, { FILEIO_SYS_CAP_TAG + E_WOULDBLOCK, "Operation would block" } }, + { FILEIO_SYS_CAP_TAG + E_BADR, { FILEIO_SYS_CAP_TAG + E_BADR, "Invalid request descriptor" } }, + { FILEIO_SYS_CAP_TAG + E_NOSTR, { FILEIO_SYS_CAP_TAG + E_NOSTR, "Device not a stream" } }, + { FILEIO_SYS_CAP_TAG + E_NODATA, { FILEIO_SYS_CAP_TAG + E_NODATA, "No data available" } }, + { FILEIO_SYS_CAP_TAG + E_OVERFLOW, { FILEIO_SYS_CAP_TAG + E_OVERFLOW, "Value too large for defined data type" } }, + { FILEIO_SYS_CAP_TAG + E_BADFD, { FILEIO_SYS_CAP_TAG + E_BADFD, "File descriptor in bad state" } }, + { FILEIO_SYS_CAP_TAG + E_RESTART, + { FILEIO_SYS_CAP_TAG + E_RESTART, "Interrupted system call should be restarted" } }, + { FILEIO_SYS_CAP_TAG + E_DQUOT, { FILEIO_SYS_CAP_TAG + E_DQUOT, "Quota exceeded" } }, + { FILEIO_SYS_CAP_TAG + E_UKERR, { FILEIO_SYS_CAP_TAG + E_UKERR, "Unknown error" } }, + { FILEIO_SYS_CAP_TAG + E_NOLCK, { FILEIO_SYS_CAP_TAG + E_NOLCK, "No record locks available" } }, + { FILEIO_SYS_CAP_TAG + E_NETUNREACH, { FILEIO_SYS_CAP_TAG + E_NETUNREACH, "Network is unreachable" } }, + { FILEIO_SYS_CAP_TAG + E_CONNECTION_FAIL, { FILEIO_SYS_CAP_TAG + E_CONNECTION_FAIL, "Connection failed" } }, + { FILEIO_SYS_CAP_TAG + E_CONNECTION_ABORT, + { FILEIO_SYS_CAP_TAG + E_CONNECTION_ABORT, "Software caused connection abort" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_DISPLAYNAME, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_DISPLAYNAME, "Invalid display name" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_URIM, { USER_FILE_MANAGER_SYS_CAP_TAG + E_URIM, "Invalid uri" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_SUFFIX, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_SUFFIX, "Invalid file extension" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_TRASH, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_TRASH, "File has been put into trash bin" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_OPEN_MODE, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_OPEN_MODE, "Invalid open mode" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_NOT_ALBUM, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_NOT_ALBUM, "The uri is not album" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_ROOT_DIR, { USER_FILE_MANAGER_SYS_CAP_TAG + E_ROOT_DIR, "Invalid root dir" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_MOVE_DENIED, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_MOVE_DENIED, "Failed to move as dir check failed" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_RENAME_DENIED, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_RENAME_DENIED, "Failed to rename as dir check failed" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_RELATIVEPATH, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_RELATIVEPATH, "Relative path not exist or invalid" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_INNER_FAIL, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_INNER_FAIL, "MediaLibrary inner fail" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_FILE_TYPE, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_FILE_TYPE, "File type is not allow in the directory" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_FILE_KEY, { USER_FILE_MANAGER_SYS_CAP_TAG + E_FILE_KEY, "Member not exist" } }, + { USER_FILE_MANAGER_SYS_CAP_TAG + E_INPUT, { USER_FILE_MANAGER_SYS_CAP_TAG + E_INPUT, "Wrong input parameter" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_IPCSS, { STORAGE_SERVICE_SYS_CAP_TAG + E_IPCSS, "IPC error" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_NOTSUPPORTEDFS, + { STORAGE_SERVICE_SYS_CAP_TAG + E_NOTSUPPORTEDFS, "Not supported filesystem" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_MOUNT, { STORAGE_SERVICE_SYS_CAP_TAG + E_MOUNT, "Failed to mount" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_UNMOUNT, { STORAGE_SERVICE_SYS_CAP_TAG + E_UNMOUNT, "Failed to unmount" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_VOLUMESTATE, + { STORAGE_SERVICE_SYS_CAP_TAG + E_VOLUMESTATE, "Incorrect volume state" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_PREPARE, + { STORAGE_SERVICE_SYS_CAP_TAG + E_PREPARE, "Prepare directory or node error" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_DELETE, + { STORAGE_SERVICE_SYS_CAP_TAG + E_DELETE, "Delete directory or node error" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_NOOBJECT, { STORAGE_SERVICE_SYS_CAP_TAG + E_NOOBJECT, "No such object" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_OUTOFRANGE, + { STORAGE_SERVICE_SYS_CAP_TAG + E_OUTOFRANGE, "User id out of range" } }, + { STORAGE_SERVICE_SYS_CAP_TAG + E_NOOBJECT, { STORAGE_SERVICE_SYS_CAP_TAG + E_NOOBJECT, "No such object" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_IPCS, { USER_FILE_SERVICE_SYS_CAP_TAG + E_IPCS, "IPC error" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_URIS, { USER_FILE_SERVICE_SYS_CAP_TAG + E_URIS, "Invalid uri" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_GETINFO, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_GETINFO, "Fail to get fileextension info" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_GETRESULT, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_GETRESULT, "Get wrong result" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_REGISTER, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_REGISTER, "Fail to register notification" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_REMOVE, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_REMOVE, "Fail to remove notification" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_INIT, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_INIT, "Fail to init notification agent" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_NOTIFY, { USER_FILE_SERVICE_SYS_CAP_TAG + E_NOTIFY, "Fail to notify agent" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CONNECT, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CONNECT, "Fail to connect file access extension ability" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CALLBACK_AND_URI_HAS_NOT_RELATIONS, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CALLBACK_AND_URI_HAS_NOT_RELATIONS, + "The uri has no relationship with the callback and cannot be unregistered" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CALLBACK_IS_NOT_REGISTER, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CALLBACK_IS_NOT_REGISTER, + "Cannot unregister the callback that has not been registered" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CAN_NOT_FIND_URI, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_CAN_NOT_FIND_URI, "Can not find registered uri" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_DO_NOT_HAVE_PARENT, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_DO_NOT_HAVE_PARENT, "Do not have parent uri" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_LOAD_SA, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_LOAD_SA, "Fail to load system ability" } }, + { USER_FILE_SERVICE_SYS_CAP_TAG + E_COUNT, { USER_FILE_SERVICE_SYS_CAP_TAG + E_COUNT, "Too many records" } }, + { E_PERMISSION, { E_PERMISSION, "Permission verification failed" } }, + { E_PERMISSION_SYS, { E_PERMISSION_SYS, "The caller is not a system application" } }, + { E_PARAMS, { E_PARAMS, "The input parameter is invalid" } }, + { E_DEVICENOTSUPPORT, { E_DEVICENOTSUPPORT, "The device doesn't support this api" } }, + { E_OSNOTSUPPORT, { E_OSNOTSUPPORT, "The os doesn't support this api" } }, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_CLOUD_NOT_READY, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_CLOUD_NOT_READY, "Cloud status not ready" } }, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_NETWORK_ERR, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_NETWORK_ERR, "Network unavailable" } }, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_BATTERY_WARNING, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_BATTERY_WARNING, "Battery level warning" } }, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_EXCEED_MAX_LIMIT, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_EXCEED_MAX_LIMIT, "Exceed the maximum limit" } }, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_DATABASE_FAILED, + { DISTRIBUTEDFILE_SERVICE_SYS_CAP_TAG + E_DATABASE_FAILED, "Database operation failed" } }, +}; + +class FsError { +public: + FsError(int errCode); + int GetErrNo() const; + const std::string &GetErrMsg() const; + ~FsError() = default; + explicit operator bool() const; + +private: + int errno_ = ERRNO_NOERR; + std::string errMsg_; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // FILEMANAGEMENT_FS_ERROR_H \ No newline at end of file diff --git a/utils/filemgmt_libfs/include/fs_result.h b/utils/filemgmt_libfs/include/fs_result.h new file mode 100644 index 0000000000000000000000000000000000000000..0aaab49eabaa8b99b1bc64ecee284209d7bf2b2b --- /dev/null +++ b/utils/filemgmt_libfs/include/fs_result.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025 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 FILEMANAGEMENT_FS_RESULT_H +#define FILEMANAGEMENT_FS_RESULT_H + +#include "fs_error.h" + +#include +#include +#include +#include + +namespace OHOS::FileManagement::ModuleFileIO { + +template +class FsResult { + using OptionalData = std::optional; + +public: + static FsResult Success() + { + return FsResult(FsError(ERRNO_NOERR), std::nullopt); + } + + static FsResult Success(const T &data) + { + return FsResult(FsError(ERRNO_NOERR), std::make_optional(data)); + } + + static FsResult Success(T &&data) + { + return FsResult(FsError(ERRNO_NOERR), std::make_optional(std::move(data))); + } + + template , int> = 0> + static FsResult Success(const char *data) + { + return FsResult(FsError(ERRNO_NOERR), std::make_optional(std::string(data))); + } + + static FsResult Error(const int32_t code) + { + return FsResult(FsError(code), std::nullopt); + } + + bool IsSuccess() const + { + return !error_; + } + + const OptionalData &GetData() const + { + return data_; + } + + OptionalData &GetData() + { + return data_; + } + + const FsError &GetError() const + { + return error_; + } + + FsResult(const FsResult &) = delete; + FsResult &operator=(const FsResult &) = delete; + + FsResult(FsResult &&other) noexcept : error_(std::move(other.error_)), data_(std::move(other.data_)) {} + + FsResult &operator=(FsResult &&other) noexcept + { + if (this != &other) { + error_ = std::move(other.error_); + data_ = std::move(other.data_); + } + return *this; + } + + ~FsResult() = default; + +private: + FsError error_; + OptionalData data_; + + FsResult(const FsError &err, const OptionalData &data) : error_(err), data_(data) {} + + FsResult(const FsError &err, OptionalData &&data) : error_(err), data_(std::move(data)) {} +}; + +template <> +class FsResult { +private: + FsError error_; + explicit FsResult(const FsError &err) : error_(err) {} + +public: + static FsResult Success() + { + return FsResult(FsError(ERRNO_NOERR)); + } + + static FsResult Error(const int32_t code) + { + return FsResult(FsError(code)); + } + + bool IsSuccess() const + { + return !error_; + } + + const FsError &GetError() const + { + return error_; + } + + FsResult(const FsResult &) = delete; + FsResult &operator=(const FsResult &) = delete; + + FsResult(FsResult &&other) noexcept : error_(std::move(other.error_)) {} + + FsResult &operator=(FsResult &&other) noexcept + { + if (this != &other) { + error_ = std::move(other.error_); + } + return *this; + } + + ~FsResult() = default; +}; + +} // namespace OHOS::FileManagement::ModuleFileIO +#endif // FILEMANAGEMENT_FS_RESULT_H \ No newline at end of file diff --git a/utils/filemgmt_libfs/src/fs_error.cpp b/utils/filemgmt_libfs/src/fs_error.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3636a7d5f966a4633f5f57b73d7d705af0196de5 --- /dev/null +++ b/utils/filemgmt_libfs/src/fs_error.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025 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 "fs_error.h" +#include "uv.h" + +namespace OHOS::FileManagement::ModuleFileIO { +using namespace std; + +static int ConvertUVCode2ErrCode(int errCode) +{ + if (errCode >= 0) { + return errCode; + } + auto uvCode = string_view(uv_err_name(errCode)); + if (uvCode2ErrCodeTable.find(uvCode) != uvCode2ErrCodeTable.end()) { + return uvCode2ErrCodeTable.at(uvCode); + } + return UNKNOWN_ERR; +} + +FsError::FsError(int errCode) +{ + int genericCode = ConvertUVCode2ErrCode(errCode); + auto it = errCodeTable.find(genericCode); + if (it != errCodeTable.end()) { + errno_ = it->second.first; + errMsg_ = it->second.second; + } else { + errno_ = errCodeTable.at(UNKNOWN_ERR).first; + errMsg_ = errCodeTable.at(UNKNOWN_ERR).second + ", errno is " + to_string(abs(errCode)); + } +} + +int FsError::GetErrNo() const +{ + return errno_; +} + +const std::string &FsError::GetErrMsg() const +{ + return errMsg_; +} + +FsError::operator bool() const +{ + return errno_ != ERRNO_NOERR; +} + +} // namespace OHOS::FileManagement::ModuleFileIO