1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "close.h"
17
18 #include <cstring>
19 #include <tuple>
20 #include <unistd.h>
21
22 #include "common_func.h"
23 #include "filemgmt_libhilog.h"
24
25 namespace OHOS {
26 namespace FileManagement {
27 namespace ModuleFileIO {
28 using namespace std;
29 using namespace OHOS::FileManagement::LibN;
30
GetFileEntity(napi_env env,napi_value objFile)31 static FileEntity *GetFileEntity(napi_env env, napi_value objFile)
32 {
33 auto fileEntity = NClass::GetEntityOf<FileEntity>(env, objFile);
34 if (!fileEntity) {
35 HILOGE("Failed to get file entity");
36 return nullptr;
37 }
38 if (!fileEntity->fd_) {
39 HILOGE("The fd of entity is not exist");
40 return nullptr;
41 }
42 return fileEntity;
43 }
44
CloseFd(int fd)45 static NError CloseFd(int fd)
46 {
47 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> close_req = {
48 new uv_fs_t, CommonFunc::fs_req_cleanup };
49 if (!close_req) {
50 HILOGE("Failed to request heap memory.");
51 return NError(ENOMEM);
52 }
53 int ret = uv_fs_close(nullptr, close_req.get(), fd, nullptr);
54 if (ret < 0) {
55 HILOGE("Failed to close file with ret: %{public}d", ret);
56 return NError(ret);
57 }
58 return NError(ERRNO_NOERR);
59 }
60
ParseJsOperand(napi_env env,napi_value fdOrFileFromJsArg)61 static tuple<bool, FileStruct> ParseJsOperand(napi_env env, napi_value fdOrFileFromJsArg)
62 {
63 auto [isFd, fd] = NVal(env, fdOrFileFromJsArg).ToInt32();
64 if (isFd && fd >= 0) {
65 return { true, FileStruct { true, fd, nullptr } };
66 }
67 if (isFd && fd < 0) {
68 return { false, FileStruct { false, -1, nullptr } };
69 }
70 auto file = GetFileEntity(env, fdOrFileFromJsArg);
71 if (file) {
72 return { true, FileStruct { false, -1, file } };
73 }
74
75 return { false, FileStruct { false, -1, nullptr } };
76 }
77
Sync(napi_env env,napi_callback_info info)78 napi_value Close::Sync(napi_env env, napi_callback_info info)
79 {
80 NFuncArg funcArg(env, info);
81 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
82 HILOGE("Number of arguments unmatched");
83 NError(EINVAL).ThrowErr(env);
84 return nullptr;
85 }
86
87 auto [resGetFirstArg, fileStruct] = ParseJsOperand(env, funcArg[NARG_POS::FIRST]);
88 if (!resGetFirstArg) {
89 HILOGI("Failed to parse fd or FileEntity from JS parameter");
90 NError(EINVAL).ThrowErr(env);
91 return nullptr;
92 }
93
94 if (fileStruct.isFd) {
95 auto err = CloseFd(fileStruct.fd);
96 if (err) {
97 err.ThrowErr(env);
98 return nullptr;
99 }
100 } else {
101 auto err = CloseFd(fileStruct.fileEntity->fd_->GetFD());
102 if (err) {
103 err.ThrowErr(env);
104 return nullptr;
105 }
106 auto fp = NClass::RemoveEntityOfFinal<FileEntity>(env, funcArg[NARG_POS::FIRST]);
107 if (!fp) {
108 NError(EINVAL).ThrowErr(env);
109 return nullptr;
110 }
111 }
112
113 return NVal::CreateUndefined(env).val_;
114 }
115
Async(napi_env env,napi_callback_info info)116 napi_value Close::Async(napi_env env, napi_callback_info info)
117 {
118 NFuncArg funcArg(env, info);
119 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
120 HILOGE("Number of arguments unmatched");
121 NError(EINVAL).ThrowErr(env);
122 return nullptr;
123 }
124
125 auto [resGetFirstArg, fileStruct] = ParseJsOperand(env, funcArg[NARG_POS::FIRST]);
126 if (!resGetFirstArg) {
127 HILOGI("Failed to parse JS operand");
128 NError(EINVAL).ThrowErr(env);
129 return nullptr;
130 }
131
132 if (!fileStruct.isFd) {
133 fileStruct.fd = fileStruct.fileEntity->fd_->GetFD();
134 fileStruct.isFd = true;
135 auto fp = NClass::RemoveEntityOfFinal<FileEntity>(env, funcArg[NARG_POS::FIRST]);
136 if (!fp) {
137 NError(EINVAL).ThrowErr(env);
138 return nullptr;
139 }
140 }
141
142 auto cbExec = [fileStruct = fileStruct]() -> NError {
143 if (fileStruct.isFd) {
144 return CloseFd(fileStruct.fd);
145 }
146 return NError(ERRNO_NOERR);
147 };
148
149 auto cbComplete = [](napi_env env, NError err) -> NVal {
150 if (err) {
151 return { env, err.GetNapiErr(env) };
152 } else {
153 return NVal::CreateUndefined(env);
154 }
155 };
156
157 size_t argc = funcArg.GetArgc();
158 NVal thisVar(env, funcArg.GetThisVar());
159 if (argc == NARG_CNT::ONE) {
160 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_CLOSE_NAME, cbExec, cbComplete).val_;
161 } else {
162 NVal cb(env, funcArg[NARG_POS::SECOND]);
163 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_CLOSE_NAME, cbExec, cbComplete).val_;
164 }
165 }
166 } // namespace ModuleFileIO
167 } // namespace FileManagement
168 } // namespace OHOS