1 /*
2 * Copyright (c) 2022-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 "file_entity.h"
17 #include "file_n_exporter.h"
18
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <memory>
23 #include <sys/file.h>
24
25 #include "filemgmt_libhilog.h"
26 #include "filemgmt_libn.h"
27 #include "../common_func.h"
28
29 namespace OHOS {
30 namespace FileManagement {
31 namespace ModuleFileIO {
32 using namespace std;
33 using namespace OHOS::FileManagement::LibN;
34
GetFileEntity(napi_env env,napi_value raf_entity)35 static FileEntity *GetFileEntity(napi_env env, napi_value raf_entity)
36 {
37 auto rafEntity = NClass::GetEntityOf<FileEntity>(env, raf_entity);
38 if (!rafEntity) {
39 HILOGE("Failed to get file entity");
40 NError(EINVAL).ThrowErr(env);
41 return nullptr;
42 }
43 if (!rafEntity->fd_) {
44 HILOGE("rafEntity fd is not exist");
45 NError(EINVAL).ThrowErr(env);
46 return nullptr;
47 }
48 return rafEntity;
49 }
50
GetFD(napi_env env,napi_callback_info info)51 napi_value FileNExporter::GetFD(napi_env env, napi_callback_info info)
52 {
53 NFuncArg funcArg(env, info);
54 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
55 HILOGE("Number of arguments unmatched");
56 NError(EINVAL).ThrowErr(env);
57 return nullptr;
58 }
59 auto rafEntity = GetFileEntity(env, funcArg.GetThisVar());
60 if (!rafEntity) {
61 HILOGE("Failed to get file entity");
62 return nullptr;
63 }
64 return NVal::CreateInt32(env, rafEntity->fd_.get()->GetFD()).val_;
65 }
66
GetExclusive(napi_env env,NFuncArg & funcArg,bool & exclusive)67 static bool GetExclusive(napi_env env, NFuncArg &funcArg, bool &exclusive)
68 {
69 bool succ = true;
70 if (funcArg.GetArgc() >= NARG_CNT::ONE && !(NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_function))) {
71 if (NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_boolean)) {
72 tie(succ, exclusive) = NVal(env, funcArg[NARG_POS::FIRST]).ToBool();
73 if (!succ) {
74 HILOGE("Invalid exclusive");
75 NError(EINVAL).ThrowErr(env);
76 }
77 } else {
78 HILOGE("Invalid exclusive");
79 NError(EINVAL).ThrowErr(env);
80 succ = false;
81 }
82 }
83 return succ;
84 }
85
Lock(napi_env env,napi_callback_info info)86 napi_value FileNExporter::Lock(napi_env env, napi_callback_info info)
87 {
88 NFuncArg funcArg(env, info);
89 if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::TWO)) {
90 HILOGE("Number of arguments unmatched");
91 NError(EINVAL).ThrowErr(env);
92 return nullptr;
93 }
94
95 auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
96 if (!fileEntity) {
97 HILOGE("Failed to get file entity");
98 NError(EINVAL).ThrowErr(env);
99 return nullptr;
100 }
101
102 bool exclusive = false;
103 if (!GetExclusive(env, funcArg, exclusive)) {
104 return nullptr;
105 }
106 auto cbExec = [exclusive, fileEntity]() -> NError {
107 int ret = 0;
108 auto mode = exclusive ? LOCK_EX : LOCK_SH;
109 ret = flock(fileEntity->fd_.get()->GetFD(), mode);
110 if (ret < 0) {
111 HILOGE("Failed to lock file");
112 return NError(errno);
113 } else {
114 return NError(ERRNO_NOERR);
115 }
116 };
117
118 auto cbCompl = [](napi_env env, NError err) -> NVal {
119 if (err) {
120 return { env, err.GetNapiErr(env) };
121 }
122 return NVal::CreateUndefined(env);
123 };
124
125 NVal thisVar(env, funcArg.GetThisVar());
126 if (funcArg.GetArgc() == NARG_CNT::ZERO || (funcArg.GetArgc() == NARG_CNT::ONE &&
127 NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_boolean))) {
128 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_LOCK_NAME, cbExec, cbCompl).val_;
129 } else {
130 int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::FIRST);
131 NVal cb(env, funcArg[cbIdx]);
132 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_LOCK_NAME, cbExec, cbCompl).val_;
133 }
134 }
135
TryLock(napi_env env,napi_callback_info info)136 napi_value FileNExporter::TryLock(napi_env env, napi_callback_info info)
137 {
138 NFuncArg funcArg(env, info);
139 if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
140 HILOGE("Number of arguments unmatched");
141 NError(EINVAL).ThrowErr(env);
142 return nullptr;
143 }
144
145 auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
146 if (!fileEntity) {
147 HILOGE("Failed to get file entity");
148 NError(EINVAL).ThrowErr(env);
149 return nullptr;
150 }
151
152 bool exclusive = false;
153 if (!GetExclusive(env, funcArg, exclusive)) {
154 return nullptr;
155 }
156
157 int ret = 0;
158 auto mode = exclusive ? LOCK_EX : LOCK_SH;
159 ret = flock(fileEntity->fd_.get()->GetFD(), mode | LOCK_NB);
160 if (ret < 0) {
161 HILOGE("Failed to try to lock file");
162 NError(errno).ThrowErr(env);
163 }
164
165 return NVal::CreateUndefined(env).val_;
166 }
167
UnLock(napi_env env,napi_callback_info info)168 napi_value FileNExporter::UnLock(napi_env env, napi_callback_info info)
169 {
170 NFuncArg funcArg(env, info);
171 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
172 HILOGE("Number of arguments unmatched");
173 NError(EINVAL).ThrowErr(env);
174 return nullptr;
175 }
176
177 auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
178 if (!fileEntity) {
179 HILOGE("Failed to get file entity");
180 NError(EINVAL).ThrowErr(env);
181 return nullptr;
182 }
183
184 int ret = 0;
185 ret = flock(fileEntity->fd_.get()->GetFD(), LOCK_UN);
186 if (ret < 0) {
187 HILOGE("Failed to unlock file");
188 NError(errno).ThrowErr(env);
189 return nullptr;
190 }
191 return NVal::CreateUndefined(env).val_;
192 }
193
Constructor(napi_env env,napi_callback_info info)194 napi_value FileNExporter::Constructor(napi_env env, napi_callback_info info)
195 {
196 NFuncArg funcArg(env, info);
197 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
198 HILOGE("Number of arguments unmatched");
199 NError(EINVAL).ThrowErr(env);
200 return nullptr;
201 }
202
203 auto rafEntity = make_unique<FileEntity>();
204 if (!NClass::SetEntityFor<FileEntity>(env, funcArg.GetThisVar(), move(rafEntity))) {
205 HILOGE("Failed to set file entity");
206 NError(EIO).ThrowErr(env);
207 return nullptr;
208 }
209 return funcArg.GetThisVar();
210 }
211
Export()212 bool FileNExporter::Export()
213 {
214 vector<napi_property_descriptor> props = {
215 NVal::DeclareNapiGetter("fd", GetFD),
216 NVal::DeclareNapiFunction("lock", Lock),
217 NVal::DeclareNapiFunction("tryLock", TryLock),
218 NVal::DeclareNapiFunction("unlock", UnLock),
219 };
220
221 string className = GetClassName();
222 bool succ = false;
223 napi_value classValue = nullptr;
224 tie(succ, classValue) = NClass::DefineClass(exports_.env_, className,
225 FileNExporter::Constructor, move(props));
226 if (!succ) {
227 HILOGE("Define class exceptions");
228 NError(EIO).ThrowErr(exports_.env_);
229 return false;
230 }
231 succ = NClass::SaveClass(exports_.env_, className, classValue);
232 if (!succ) {
233 HILOGE("Save class exceptions");
234 NError(EIO).ThrowErr(exports_.env_);
235 return false;
236 }
237
238 return exports_.AddProp(className, classValue);
239 }
240
GetClassName()241 string FileNExporter::GetClassName()
242 {
243 return FileNExporter::className_;
244 }
245
FileNExporter(napi_env env,napi_value exports)246 FileNExporter::FileNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
~FileNExporter()247 FileNExporter::~FileNExporter() {}
248 } // namespace ModuleFileIO
249 } // namespace FileManagement
250 } // namespace OHOS