diff --git a/interfaces/kits/js/src/mod_fs/class_file/file_entity.h b/interfaces/kits/js/src/mod_fs/class_file/file_entity.h index 6bedf0d00a7e0ac82e9ca7cf65196a9adb721dae..9687c7c7de7ea2f4161ec5724f4a4fcceafcf043 100644 --- a/interfaces/kits/js/src/mod_fs/class_file/file_entity.h +++ b/interfaces/kits/js/src/mod_fs/class_file/file_entity.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 @@ -16,10 +16,14 @@ #ifndef INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_FILE_FILE_ENTITY_H #define INTERFACES_KITS_JS_SRC_MOD_FS_CLASS_FILE_FILE_ENTITY_H +#include #include +#include +#include #include #include "fd_guard.h" +#include "filemgmt_libhilog.h" namespace OHOS { namespace FileManagement { @@ -28,6 +32,20 @@ struct FileEntity { std::unique_ptr fd_ = { nullptr }; std::string path_; std::string uri_; + + virtual ~FileEntity() + { + int32_t fd = fd_.get()->GetFD(); + int ret = flock(fd, LOCK_UN); + if (ret == 0) { + struct stat buf; + if (fstat(fd, &buf) == 0) { + HILOGI("Unlock succeeded inode = %{public}" PRIu64, buf.st_ino); + } else { + HILOGI("Failed to get inode number"); + } + } + } }; } // namespace ModuleFileIO } // namespace FileManagement diff --git a/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.cpp b/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.cpp index 6d7ad806dee9540f40ef6d5a84a92cb57be920f3..5ad575a3c1b035c2935dde1d1c4d963f4d65b303 100644 --- a/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.cpp +++ b/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 @@ -20,6 +20,7 @@ #include #include #include +#include #include "filemgmt_libhilog.h" #include "filemgmt_libn.h" @@ -63,6 +64,133 @@ napi_value FileNExporter::GetFD(napi_env env, napi_callback_info info) return NVal::CreateInt32(env, rafEntity->fd_.get()->GetFD()).val_; } +static bool GetExclusive(napi_env env, NFuncArg &funcArg, bool &exclusive) +{ + bool succ = true; + if (funcArg.GetArgc() >= NARG_CNT::ONE && !(NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_function))) { + if (NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_boolean)) { + tie(succ, exclusive) = NVal(env, funcArg[NARG_POS::FIRST]).ToBool(); + if (!succ) { + HILOGE("Invalid exclusive"); + NError(EINVAL).ThrowErr(env); + } + } else { + HILOGE("Invalid exclusive"); + NError(EINVAL).ThrowErr(env); + succ = false; + } + } + return succ; +} + +napi_value FileNExporter::Lock(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::TWO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto fileEntity = GetFileEntity(env, funcArg.GetThisVar()); + if (!fileEntity) { + HILOGE("Failed to get file entity"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + bool exclusive = false; + if (!GetExclusive(env, funcArg, exclusive)) { + return nullptr; + } + auto cbExec = [exclusive, fileEntity]() -> NError { + 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 NError(errno); + } else { + return NError(ERRNO_NOERR); + } + }; + + auto cbCompl = [](napi_env env, NError err) -> NVal { + if (err) { + return { env, err.GetNapiErr(env) }; + } + return NVal::CreateUndefined(env); + }; + + NVal thisVar(env, funcArg.GetThisVar()); + if (funcArg.GetArgc() == NARG_CNT::ZERO || (funcArg.GetArgc() == NARG_CNT::ONE && + NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_boolean))) { + return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_LOCK_NAME, cbExec, cbCompl).val_; + } else { + int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::FIRST); + NVal cb(env, funcArg[cbIdx]); + return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_LOCK_NAME, cbExec, cbCompl).val_; + } +} + +napi_value FileNExporter::TryLock(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto fileEntity = GetFileEntity(env, funcArg.GetThisVar()); + if (!fileEntity) { + HILOGE("Failed to get file entity"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + bool exclusive = false; + if(!GetExclusive(env, funcArg, exclusive)) { + return nullptr; + } + + 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"); + NError(errno).ThrowErr(env); + } + + return NVal::CreateUndefined(env).val_; +} + +napi_value FileNExporter::UnLock(napi_env env, napi_callback_info info) +{ + NFuncArg funcArg(env, info); + if (!funcArg.InitArgs(NARG_CNT::ZERO)) { + HILOGE("Number of arguments unmatched"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + auto fileEntity = GetFileEntity(env, funcArg.GetThisVar()); + if (!fileEntity) { + HILOGE("Failed to get file entity"); + NError(EINVAL).ThrowErr(env); + return nullptr; + } + + int ret = 0; + ret = flock(fileEntity->fd_.get()->GetFD(), LOCK_UN); + if (ret < 0) { + HILOGE("Failed to unlock file"); + NError(errno).ThrowErr(env); + return nullptr; + } + return NVal::CreateUndefined(env).val_; +} + napi_value FileNExporter::Constructor(napi_env env, napi_callback_info info) { NFuncArg funcArg(env, info); @@ -85,6 +213,9 @@ bool FileNExporter::Export() { vector props = { NVal::DeclareNapiGetter("fd", GetFD), + NVal::DeclareNapiFunction("lock", Lock), + NVal::DeclareNapiFunction("tryLock", TryLock), + NVal::DeclareNapiFunction("unlock", UnLock), }; string className = GetClassName(); diff --git a/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.h b/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.h index f79ef539ded0b0a17ab6c3cd8630ccae8d6072c9..28cee081f8891af4f59fbfbb6fd2ce8077a0794d 100644 --- a/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.h +++ b/interfaces/kits/js/src/mod_fs/class_file/file_n_exporter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Huawei Device Co., Ltd. + * 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 @@ -31,9 +31,14 @@ public: static napi_value Constructor(napi_env env, napi_callback_info cbinfo); static napi_value GetFD(napi_env env, napi_callback_info cbinfo); + static napi_value Lock(napi_env env, napi_callback_info cbinfo); + static napi_value TryLock(napi_env env, napi_callback_info cbinfo); + static napi_value UnLock(napi_env env, napi_callback_info cbinfo); FileNExporter(napi_env env, napi_value exports); ~FileNExporter() override; }; + +const std::string PROCEDURE_LOCK_NAME = "FileIOFileLock"; } // namespace ModuleFileIO } // namespace FileManagement } // namespace OHOS diff --git a/utils/filemgmt_libn/include/n_error.h b/utils/filemgmt_libn/include/n_error.h index 589e996e06cac1f977e2e77bc185bb2a41353d20..4894a38e6e6bbf0783314410bb77b483ccb03922 100644 --- a/utils/filemgmt_libn/include/n_error.h +++ b/utils/filemgmt_libn/include/n_error.h @@ -77,7 +77,8 @@ enum ErrCodeSuffixOfFileIO { E_BADFD, E_RESTART, E_DQUOT, - E_UKERR + E_UKERR, + E_NOLCK }; enum ErrCodeSuffixOfUserFileManager { @@ -163,6 +164,7 @@ const std::unordered_map> errCodeTable { { ERESTART, { FILEIO_SYS_CAP_TAG + E_RESTART, "Interrupted system call should be restarted" } }, { EDQUOT, { FILEIO_SYS_CAP_TAG + E_DQUOT, "Quota exceeded" } }, { UNKROWN_ERR, { FILEIO_SYS_CAP_TAG + E_UKERR, "Unknown error" } }, + { ENOLCK, { FILEIO_SYS_CAP_TAG + E_NOLCK, "No record locks available" } }, { 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" } }, @@ -206,6 +208,7 @@ const std::unordered_map> errCodeTable { "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" } }, { 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" } },